/**
 * Created by wuzebo on 2017/11/29.
 */
require=(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
  (function (global){
    /*!
     * The buffer module from node.js, for the browser.
     *
     * @author   Feross Aboukhadijeh <feross@feross.org> <http://feross.org>
     * @license  MIT
     */
    /* eslint-disable no-proto */

    'use strict'

    var base64 = require('base64-js')
    var ieee754 = require('ieee754')
    var isArray = require('isarray')

    exports.Buffer = Buffer
    exports.SlowBuffer = SlowBuffer
    exports.INSPECT_MAX_BYTES = 50
    Buffer.poolSize = 8192 // not used by this implementation

    var rootParent = {}

    /**
     * If `Buffer.TYPED_ARRAY_SUPPORT`:
     *   === true    Use Uint8Array implementation (fastest)
     *   === false   Use Object implementation (most compatible, even IE6)
     *
     * Browsers that support typed arrays are IE 10+, Firefox 4+, Chrome 7+, Safari 5.1+,
     * Opera 11.6+, iOS 4.2+.
     *
     * Due to various browser bugs, sometimes the Object implementation will be used even
     * when the browser supports typed arrays.
     *
     * Note:
     *
     *   - Firefox 4-29 lacks support for adding new properties to `Uint8Array` instances,
     *     See: https://bugzilla.mozilla.org/show_bug.cgi?id=695438.
     *
     *   - Safari 5-7 lacks support for changing the `Object.prototype.constructor` property
     *     on objects.
     *
     *   - Chrome 9-10 is missing the `TypedArray.prototype.subarray` function.
     *
     *   - IE10 has a broken `TypedArray.prototype.subarray` function which returns arrays of
     *     incorrect length in some situations.

     * We detect these buggy browsers and set `Buffer.TYPED_ARRAY_SUPPORT` to `false` so they
     * get the Object implementation, which is slower but behaves correctly.
     */
    Buffer.TYPED_ARRAY_SUPPORT = global.TYPED_ARRAY_SUPPORT !== undefined
      ? global.TYPED_ARRAY_SUPPORT
      : typedArraySupport()

    function typedArraySupport () {
      function Bar () {}
      try {
        var arr = new Uint8Array(1)
        arr.foo = function () { return 42 }
        arr.constructor = Bar
        return arr.foo() === 42 && // typed array instances can be augmented
          arr.constructor === Bar && // constructor can be set
          typeof arr.subarray === 'function' && // chrome 9-10 lack `subarray`
          arr.subarray(1, 1).byteLength === 0 // ie10 has broken `subarray`
      } catch (e) {
        return false
      }
    }

    function kMaxLength () {
      return Buffer.TYPED_ARRAY_SUPPORT
        ? 0x7fffffff
        : 0x3fffffff
    }

    /**
     * Class: Buffer
     * =============
     *
     * The Buffer constructor returns instances of `Uint8Array` that are augmented
     * with function properties for all the node `Buffer` API functions. We use
     * `Uint8Array` so that square bracket notation works as expected -- it returns
     * a single octet.
     *
     * By augmenting the instances, we can avoid modifying the `Uint8Array`
     * prototype.
     */
    function Buffer (arg) {
      if (!(this instanceof Buffer)) {
        // Avoid going through an ArgumentsAdaptorTrampoline in the common case.
        if (arguments.length > 1) return new Buffer(arg, arguments[1])
        return new Buffer(arg)
      }

      if (!Buffer.TYPED_ARRAY_SUPPORT) {
        this.length = 0
        this.parent = undefined
      }

      // Common case.
      if (typeof arg === 'number') {
        return fromNumber(this, arg)
      }

      // Slightly less common case.
      if (typeof arg === 'string') {
        return fromString(this, arg, arguments.length > 1 ? arguments[1] : 'utf8')
      }

      // Unusual.
      return fromObject(this, arg)
    }

    function fromNumber (that, length) {
      that = allocate(that, length < 0 ? 0 : checked(length) | 0)
      if (!Buffer.TYPED_ARRAY_SUPPORT) {
        for (var i = 0; i < length; i++) {
          that[i] = 0
        }
      }
      return that
    }

    function fromString (that, string, encoding) {
      if (typeof encoding !== 'string' || encoding === '') encoding = 'utf8'

      // Assumption: byteLength() return value is always < kMaxLength.
      var length = byteLength(string, encoding) | 0
      that = allocate(that, length)

      that.write(string, encoding)
      return that
    }

    function fromObject (that, object) {
      if (Buffer.isBuffer(object)) return fromBuffer(that, object)

      if (isArray(object)) return fromArray(that, object)

      if (object == null) {
        throw new TypeError('must start with number, buffer, array or string')
      }

      if (typeof ArrayBuffer !== 'undefined') {
        if (object.buffer instanceof ArrayBuffer) {
          return fromTypedArray(that, object)
        }
        if (object instanceof ArrayBuffer) {
          return fromArrayBuffer(that, object)
        }
      }

      if (object.length) return fromArrayLike(that, object)

      return fromJsonObject(that, object)
    }

    function fromBuffer (that, buffer) {
      var length = checked(buffer.length) | 0
      that = allocate(that, length)
      buffer.copy(that, 0, 0, length)
      return that
    }

    function fromArray (that, array) {
      var length = checked(array.length) | 0
      that = allocate(that, length)
      for (var i = 0; i < length; i += 1) {
        that[i] = array[i] & 255
      }
      return that
    }

// Duplicate of fromArray() to keep fromArray() monomorphic.
    function fromTypedArray (that, array) {
      var length = checked(array.length) | 0
      that = allocate(that, length)
      // Truncating the elements is probably not what people expect from typed
      // arrays with BYTES_PER_ELEMENT > 1 but it's compatible with the behavior
      // of the old Buffer constructor.
      for (var i = 0; i < length; i += 1) {
        that[i] = array[i] & 255
      }
      return that
    }

    function fromArrayBuffer (that, array) {
      if (Buffer.TYPED_ARRAY_SUPPORT) {
        // Return an augmented `Uint8Array` instance, for best performance
        array.byteLength
        that = Buffer._augment(new Uint8Array(array))
      } else {
        // Fallback: Return an object instance of the Buffer class
        that = fromTypedArray(that, new Uint8Array(array))
      }
      return that
    }

    function fromArrayLike (that, array) {
      var length = checked(array.length) | 0
      that = allocate(that, length)
      for (var i = 0; i < length; i += 1) {
        that[i] = array[i] & 255
      }
      return that
    }

// Deserialize { type: 'Buffer', data: [1,2,3,...] } into a Buffer object.
// Returns a zero-length buffer for inputs that don't conform to the spec.
    function fromJsonObject (that, object) {
      var array
      var length = 0

      if (object.type === 'Buffer' && isArray(object.data)) {
        array = object.data
        length = checked(array.length) | 0
      }
      that = allocate(that, length)

      for (var i = 0; i < length; i += 1) {
        that[i] = array[i] & 255
      }
      return that
    }

    if (Buffer.TYPED_ARRAY_SUPPORT) {
      Buffer.prototype.__proto__ = Uint8Array.prototype
      Buffer.__proto__ = Uint8Array
    } else {
      // pre-set for values that may exist in the future
      Buffer.prototype.length = undefined
      Buffer.prototype.parent = undefined
    }

    function allocate (that, length) {
      if (Buffer.TYPED_ARRAY_SUPPORT) {
        // Return an augmented `Uint8Array` instance, for best performance
        that = Buffer._augment(new Uint8Array(length))
        that.__proto__ = Buffer.prototype
      } else {
        // Fallback: Return an object instance of the Buffer class
        that.length = length
        that._isBuffer = true
      }

      var fromPool = length !== 0 && length <= Buffer.poolSize >>> 1
      if (fromPool) that.parent = rootParent

      return that
    }

    function checked (length) {
      // Note: cannot use `length < kMaxLength` here because that fails when
      // length is NaN (which is otherwise coerced to zero.)
      if (length >= kMaxLength()) {
        throw new RangeError('Attempt to allocate Buffer larger than maximum ' +
          'size: 0x' + kMaxLength().toString(16) + ' bytes')
      }
      return length | 0
    }

    function SlowBuffer (subject, encoding) {
      if (!(this instanceof SlowBuffer)) return new SlowBuffer(subject, encoding)

      var buf = new Buffer(subject, encoding)
      delete buf.parent
      return buf
    }

    Buffer.isBuffer = function isBuffer (b) {
      return !!(b != null && b._isBuffer)
    }

    Buffer.compare = function compare (a, b) {
      if (!Buffer.isBuffer(a) || !Buffer.isBuffer(b)) {
        throw new TypeError('Arguments must be Buffers')
      }

      if (a === b) return 0

      var x = a.length
      var y = b.length

      var i = 0
      var len = Math.min(x, y)
      while (i < len) {
        if (a[i] !== b[i]) break

        ++i
      }

      if (i !== len) {
        x = a[i]
        y = b[i]
      }

      if (x < y) return -1
      if (y < x) return 1
      return 0
    }

    Buffer.isEncoding = function isEncoding (encoding) {
      switch (String(encoding).toLowerCase()) {
        case 'hex':
        case 'utf8':
        case 'utf-8':
        case 'ascii':
        case 'binary':
        case 'base64':
        case 'raw':
        case 'ucs2':
        case 'ucs-2':
        case 'utf16le':
        case 'utf-16le':
          return true
        default:
          return false
      }
    }

    Buffer.concat = function concat (list, length) {
      if (!isArray(list)) throw new TypeError('list argument must be an Array of Buffers.')

      if (list.length === 0) {
        return new Buffer(0)
      }

      var i
      if (length === undefined) {
        length = 0
        for (i = 0; i < list.length; i++) {
          length += list[i].length
        }
      }

      var buf = new Buffer(length)
      var pos = 0
      for (i = 0; i < list.length; i++) {
        var item = list[i]
        item.copy(buf, pos)
        pos += item.length
      }
      return buf
    }

    function byteLength (string, encoding) {
      if (typeof string !== 'string') string = '' + string

      var len = string.length
      if (len === 0) return 0

      // Use a for loop to avoid recursion
      var loweredCase = false
      for (;;) {
        switch (encoding) {
          case 'ascii':
          case 'binary':
          // Deprecated
          case 'raw':
          case 'raws':
            return len
          case 'utf8':
          case 'utf-8':
            return utf8ToBytes(string).length
          case 'ucs2':
          case 'ucs-2':
          case 'utf16le':
          case 'utf-16le':
            return len * 2
          case 'hex':
            return len >>> 1
          case 'base64':
            return base64ToBytes(string).length
          default:
            if (loweredCase) return utf8ToBytes(string).length // assume utf8
            encoding = ('' + encoding).toLowerCase()
            loweredCase = true
        }
      }
    }
    Buffer.byteLength = byteLength

    function slowToString (encoding, start, end) {
      var loweredCase = false

      start = start | 0
      end = end === undefined || end === Infinity ? this.length : end | 0

      if (!encoding) encoding = 'utf8'
      if (start < 0) start = 0
      if (end > this.length) end = this.length
      if (end <= start) return ''

      while (true) {
        switch (encoding) {
          case 'hex':
            return hexSlice(this, start, end)

          case 'utf8':
          case 'utf-8':
            return utf8Slice(this, start, end)

          case 'ascii':
            return asciiSlice(this, start, end)

          case 'binary':
            return binarySlice(this, start, end)

          case 'base64':
            return base64Slice(this, start, end)

          case 'ucs2':
          case 'ucs-2':
          case 'utf16le':
          case 'utf-16le':
            return utf16leSlice(this, start, end)

          default:
            if (loweredCase) throw new TypeError('Unknown encoding: ' + encoding)
            encoding = (encoding + '').toLowerCase()
            loweredCase = true
        }
      }
    }

    Buffer.prototype.toString = function toString () {
      var length = this.length | 0
      if (length === 0) return ''
      if (arguments.length === 0) return utf8Slice(this, 0, length)
      return slowToString.apply(this, arguments)
    }

    Buffer.prototype.equals = function equals (b) {
      if (!Buffer.isBuffer(b)) throw new TypeError('Argument must be a Buffer')
      if (this === b) return true
      return Buffer.compare(this, b) === 0
    }

    Buffer.prototype.inspect = function inspect () {
      var str = ''
      var max = exports.INSPECT_MAX_BYTES
      if (this.length > 0) {
        str = this.toString('hex', 0, max).match(/.{2}/g).join(' ')
        if (this.length > max) str += ' ... '
      }
      return '<Buffer ' + str + '>'
    }

    Buffer.prototype.compare = function compare (b) {
      if (!Buffer.isBuffer(b)) throw new TypeError('Argument must be a Buffer')
      if (this === b) return 0
      return Buffer.compare(this, b)
    }

    Buffer.prototype.indexOf = function indexOf (val, byteOffset) {
      if (byteOffset > 0x7fffffff) byteOffset = 0x7fffffff
      else if (byteOffset < -0x80000000) byteOffset = -0x80000000
      byteOffset >>= 0

      if (this.length === 0) return -1
      if (byteOffset >= this.length) return -1

      // Negative offsets start from the end of the buffer
      if (byteOffset < 0) byteOffset = Math.max(this.length + byteOffset, 0)

      if (typeof val === 'string') {
        if (val.length === 0) return -1 // special case: looking for empty string always fails
        return String.prototype.indexOf.call(this, val, byteOffset)
      }
      if (Buffer.isBuffer(val)) {
        return arrayIndexOf(this, val, byteOffset)
      }
      if (typeof val === 'number') {
        if (Buffer.TYPED_ARRAY_SUPPORT && Uint8Array.prototype.indexOf === 'function') {
          return Uint8Array.prototype.indexOf.call(this, val, byteOffset)
        }
        return arrayIndexOf(this, [ val ], byteOffset)
      }

      function arrayIndexOf (arr, val, byteOffset) {
        var foundIndex = -1
        for (var i = 0; byteOffset + i < arr.length; i++) {
          if (arr[byteOffset + i] === val[foundIndex === -1 ? 0 : i - foundIndex]) {
            if (foundIndex === -1) foundIndex = i
            if (i - foundIndex + 1 === val.length) return byteOffset + foundIndex
          } else {
            foundIndex = -1
          }
        }
        return -1
      }

      throw new TypeError('val must be string, number or Buffer')
    }

// `get` is deprecated
    Buffer.prototype.get = function get (offset) {
      console.log('.get() is deprecated. Access using array indexes instead.')
      return this.readUInt8(offset)
    }

// `set` is deprecated
    Buffer.prototype.set = function set (v, offset) {
      console.log('.set() is deprecated. Access using array indexes instead.')
      return this.writeUInt8(v, offset)
    }

    function hexWrite (buf, string, offset, length) {
      offset = Number(offset) || 0
      var remaining = buf.length - offset
      if (!length) {
        length = remaining
      } else {
        length = Number(length)
        if (length > remaining) {
          length = remaining
        }
      }

      // must be an even number of digits
      var strLen = string.length
      if (strLen % 2 !== 0) throw new Error('Invalid hex string')

      if (length > strLen / 2) {
        length = strLen / 2
      }
      for (var i = 0; i < length; i++) {
        var parsed = parseInt(string.substr(i * 2, 2), 16)
        if (isNaN(parsed)) throw new Error('Invalid hex string')
        buf[offset + i] = parsed
      }
      return i
    }

    function utf8Write (buf, string, offset, length) {
      return blitBuffer(utf8ToBytes(string, buf.length - offset), buf, offset, length)
    }

    function asciiWrite (buf, string, offset, length) {
      return blitBuffer(asciiToBytes(string), buf, offset, length)
    }

    function binaryWrite (buf, string, offset, length) {
      return asciiWrite(buf, string, offset, length)
    }

    function base64Write (buf, string, offset, length) {
      return blitBuffer(base64ToBytes(string), buf, offset, length)
    }

    function ucs2Write (buf, string, offset, length) {
      return blitBuffer(utf16leToBytes(string, buf.length - offset), buf, offset, length)
    }

    Buffer.prototype.write = function write (string, offset, length, encoding) {
      // Buffer#write(string)
      if (offset === undefined) {
        encoding = 'utf8'
        length = this.length
        offset = 0
        // Buffer#write(string, encoding)
      } else if (length === undefined && typeof offset === 'string') {
        encoding = offset
        length = this.length
        offset = 0
        // Buffer#write(string, offset[, length][, encoding])
      } else if (isFinite(offset)) {
        offset = offset | 0
        if (isFinite(length)) {
          length = length | 0
          if (encoding === undefined) encoding = 'utf8'
        } else {
          encoding = length
          length = undefined
        }
        // legacy write(string, encoding, offset, length) - remove in v0.13
      } else {
        var swap = encoding
        encoding = offset
        offset = length | 0
        length = swap
      }

      var remaining = this.length - offset
      if (length === undefined || length > remaining) length = remaining

      if ((string.length > 0 && (length < 0 || offset < 0)) || offset > this.length) {
        throw new RangeError('attempt to write outside buffer bounds')
      }

      if (!encoding) encoding = 'utf8'

      var loweredCase = false
      for (;;) {
        switch (encoding) {
          case 'hex':
            return hexWrite(this, string, offset, length)

          case 'utf8':
          case 'utf-8':
            return utf8Write(this, string, offset, length)

          case 'ascii':
            return asciiWrite(this, string, offset, length)

          case 'binary':
            return binaryWrite(this, string, offset, length)

          case 'base64':
            // Warning: maxLength not taken into account in base64Write
            return base64Write(this, string, offset, length)

          case 'ucs2':
          case 'ucs-2':
          case 'utf16le':
          case 'utf-16le':
            return ucs2Write(this, string, offset, length)

          default:
            if (loweredCase) throw new TypeError('Unknown encoding: ' + encoding)
            encoding = ('' + encoding).toLowerCase()
            loweredCase = true
        }
      }
    }

    Buffer.prototype.toJSON = function toJSON () {
      return {
        type: 'Buffer',
        data: Array.prototype.slice.call(this._arr || this, 0)
      }
    }

    function base64Slice (buf, start, end) {
      if (start === 0 && end === buf.length) {
        return base64.fromByteArray(buf)
      } else {
        return base64.fromByteArray(buf.slice(start, end))
      }
    }

    function utf8Slice (buf, start, end) {
      end = Math.min(buf.length, end)
      var res = []

      var i = start
      while (i < end) {
        var firstByte = buf[i]
        var codePoint = null
        var bytesPerSequence = (firstByte > 0xEF) ? 4
          : (firstByte > 0xDF) ? 3
            : (firstByte > 0xBF) ? 2
              : 1

        if (i + bytesPerSequence <= end) {
          var secondByte, thirdByte, fourthByte, tempCodePoint

          switch (bytesPerSequence) {
            case 1:
              if (firstByte < 0x80) {
                codePoint = firstByte
              }
              break
            case 2:
              secondByte = buf[i + 1]
              if ((secondByte & 0xC0) === 0x80) {
                tempCodePoint = (firstByte & 0x1F) << 0x6 | (secondByte & 0x3F)
                if (tempCodePoint > 0x7F) {
                  codePoint = tempCodePoint
                }
              }
              break
            case 3:
              secondByte = buf[i + 1]
              thirdByte = buf[i + 2]
              if ((secondByte & 0xC0) === 0x80 && (thirdByte & 0xC0) === 0x80) {
                tempCodePoint = (firstByte & 0xF) << 0xC | (secondByte & 0x3F) << 0x6 | (thirdByte & 0x3F)
                if (tempCodePoint > 0x7FF && (tempCodePoint < 0xD800 || tempCodePoint > 0xDFFF)) {
                  codePoint = tempCodePoint
                }
              }
              break
            case 4:
              secondByte = buf[i + 1]
              thirdByte = buf[i + 2]
              fourthByte = buf[i + 3]
              if ((secondByte & 0xC0) === 0x80 && (thirdByte & 0xC0) === 0x80 && (fourthByte & 0xC0) === 0x80) {
                tempCodePoint = (firstByte & 0xF) << 0x12 | (secondByte & 0x3F) << 0xC | (thirdByte & 0x3F) << 0x6 | (fourthByte & 0x3F)
                if (tempCodePoint > 0xFFFF && tempCodePoint < 0x110000) {
                  codePoint = tempCodePoint
                }
              }
          }
        }

        if (codePoint === null) {
          // we did not generate a valid codePoint so insert a
          // replacement char (U+FFFD) and advance only 1 byte
          codePoint = 0xFFFD
          bytesPerSequence = 1
        } else if (codePoint > 0xFFFF) {
          // encode to utf16 (surrogate pair dance)
          codePoint -= 0x10000
          res.push(codePoint >>> 10 & 0x3FF | 0xD800)
          codePoint = 0xDC00 | codePoint & 0x3FF
        }

        res.push(codePoint)
        i += bytesPerSequence
      }

      return decodeCodePointsArray(res)
    }

// Based on http://stackoverflow.com/a/22747272/680742, the browser with
// the lowest limit is Chrome, with 0x10000 args.
// We go 1 magnitude less, for safety
    var MAX_ARGUMENTS_LENGTH = 0x1000

    function decodeCodePointsArray (codePoints) {
      var len = codePoints.length
      if (len <= MAX_ARGUMENTS_LENGTH) {
        return String.fromCharCode.apply(String, codePoints) // avoid extra slice()
      }

      // Decode in chunks to avoid "call stack size exceeded".
      var res = ''
      var i = 0
      while (i < len) {
        res += String.fromCharCode.apply(
          String,
          codePoints.slice(i, i += MAX_ARGUMENTS_LENGTH)
        )
      }
      return res
    }

    function asciiSlice (buf, start, end) {
      var ret = ''
      end = Math.min(buf.length, end)

      for (var i = start; i < end; i++) {
        ret += String.fromCharCode(buf[i] & 0x7F)
      }
      return ret
    }

    function binarySlice (buf, start, end) {
      var ret = ''
      end = Math.min(buf.length, end)

      for (var i = start; i < end; i++) {
        ret += String.fromCharCode(buf[i])
      }
      return ret
    }

    function hexSlice (buf, start, end) {
      var len = buf.length

      if (!start || start < 0) start = 0
      if (!end || end < 0 || end > len) end = len

      var out = ''
      for (var i = start; i < end; i++) {
        out += toHex(buf[i])
      }
      return out
    }

    function utf16leSlice (buf, start, end) {
      var bytes = buf.slice(start, end)
      var res = ''
      for (var i = 0; i < bytes.length; i += 2) {
        res += String.fromCharCode(bytes[i] + bytes[i + 1] * 256)
      }
      return res
    }

    Buffer.prototype.slice = function slice (start, end) {
      var len = this.length
      start = ~~start
      end = end === undefined ? len : ~~end

      if (start < 0) {
        start += len
        if (start < 0) start = 0
      } else if (start > len) {
        start = len
      }

      if (end < 0) {
        end += len
        if (end < 0) end = 0
      } else if (end > len) {
        end = len
      }

      if (end < start) end = start

      var newBuf
      if (Buffer.TYPED_ARRAY_SUPPORT) {
        newBuf = Buffer._augment(this.subarray(start, end))
      } else {
        var sliceLen = end - start
        newBuf = new Buffer(sliceLen, undefined)
        for (var i = 0; i < sliceLen; i++) {
          newBuf[i] = this[i + start]
        }
      }

      if (newBuf.length) newBuf.parent = this.parent || this

      return newBuf
    }

    /*
     * Need to make sure that buffer isn't trying to write out of bounds.
     */
    function checkOffset (offset, ext, length) {
      if ((offset % 1) !== 0 || offset < 0) throw new RangeError('offset is not uint')
      if (offset + ext > length) throw new RangeError('Trying to access beyond buffer length')
    }

    Buffer.prototype.readUIntLE = function readUIntLE (offset, byteLength, noAssert) {
      offset = offset | 0
      byteLength = byteLength | 0
      if (!noAssert) checkOffset(offset, byteLength, this.length)

      var val = this[offset]
      var mul = 1
      var i = 0
      while (++i < byteLength && (mul *= 0x100)) {
        val += this[offset + i] * mul
      }

      return val
    }

    Buffer.prototype.readUIntBE = function readUIntBE (offset, byteLength, noAssert) {
      offset = offset | 0
      byteLength = byteLength | 0
      if (!noAssert) {
        checkOffset(offset, byteLength, this.length)
      }

      var val = this[offset + --byteLength]
      var mul = 1
      while (byteLength > 0 && (mul *= 0x100)) {
        val += this[offset + --byteLength] * mul
      }

      return val
    }

    Buffer.prototype.readUInt8 = function readUInt8 (offset, noAssert) {
      if (!noAssert) checkOffset(offset, 1, this.length)
      return this[offset]
    }

    Buffer.prototype.readUInt16LE = function readUInt16LE (offset, noAssert) {
      if (!noAssert) checkOffset(offset, 2, this.length)
      return this[offset] | (this[offset + 1] << 8)
    }

    Buffer.prototype.readUInt16BE = function readUInt16BE (offset, noAssert) {
      if (!noAssert) checkOffset(offset, 2, this.length)
      return (this[offset] << 8) | this[offset + 1]
    }

    Buffer.prototype.readUInt32LE = function readUInt32LE (offset, noAssert) {
      if (!noAssert) checkOffset(offset, 4, this.length)

      return ((this[offset]) |
        (this[offset + 1] << 8) |
        (this[offset + 2] << 16)) +
        (this[offset + 3] * 0x1000000)
    }

    Buffer.prototype.readUInt32BE = function readUInt32BE (offset, noAssert) {
      if (!noAssert) checkOffset(offset, 4, this.length)

      return (this[offset] * 0x1000000) +
        ((this[offset + 1] << 16) |
        (this[offset + 2] << 8) |
        this[offset + 3])
    }

    Buffer.prototype.readIntLE = function readIntLE (offset, byteLength, noAssert) {
      offset = offset | 0
      byteLength = byteLength | 0
      if (!noAssert) checkOffset(offset, byteLength, this.length)

      var val = this[offset]
      var mul = 1
      var i = 0
      while (++i < byteLength && (mul *= 0x100)) {
        val += this[offset + i] * mul
      }
      mul *= 0x80

      if (val >= mul) val -= Math.pow(2, 8 * byteLength)

      return val
    }

    Buffer.prototype.readIntBE = function readIntBE (offset, byteLength, noAssert) {
      offset = offset | 0
      byteLength = byteLength | 0
      if (!noAssert) checkOffset(offset, byteLength, this.length)

      var i = byteLength
      var mul = 1
      var val = this[offset + --i]
      while (i > 0 && (mul *= 0x100)) {
        val += this[offset + --i] * mul
      }
      mul *= 0x80

      if (val >= mul) val -= Math.pow(2, 8 * byteLength)

      return val
    }

    Buffer.prototype.readInt8 = function readInt8 (offset, noAssert) {
      if (!noAssert) checkOffset(offset, 1, this.length)
      if (!(this[offset] & 0x80)) return (this[offset])
      return ((0xff - this[offset] + 1) * -1)
    }

    Buffer.prototype.readInt16LE = function readInt16LE (offset, noAssert) {
      if (!noAssert) checkOffset(offset, 2, this.length)
      var val = this[offset] | (this[offset + 1] << 8)
      return (val & 0x8000) ? val | 0xFFFF0000 : val
    }

    Buffer.prototype.readInt16BE = function readInt16BE (offset, noAssert) {
      if (!noAssert) checkOffset(offset, 2, this.length)
      var val = this[offset + 1] | (this[offset] << 8)
      return (val & 0x8000) ? val | 0xFFFF0000 : val
    }

    Buffer.prototype.readInt32LE = function readInt32LE (offset, noAssert) {
      if (!noAssert) checkOffset(offset, 4, this.length)

      return (this[offset]) |
        (this[offset + 1] << 8) |
        (this[offset + 2] << 16) |
        (this[offset + 3] << 24)
    }

    Buffer.prototype.readInt32BE = function readInt32BE (offset, noAssert) {
      if (!noAssert) checkOffset(offset, 4, this.length)

      return (this[offset] << 24) |
        (this[offset + 1] << 16) |
        (this[offset + 2] << 8) |
        (this[offset + 3])
    }

    Buffer.prototype.readFloatLE = function readFloatLE (offset, noAssert) {
      if (!noAssert) checkOffset(offset, 4, this.length)
      return ieee754.read(this, offset, true, 23, 4)
    }

    Buffer.prototype.readFloatBE = function readFloatBE (offset, noAssert) {
      if (!noAssert) checkOffset(offset, 4, this.length)
      return ieee754.read(this, offset, false, 23, 4)
    }

    Buffer.prototype.readDoubleLE = function readDoubleLE (offset, noAssert) {
      if (!noAssert) checkOffset(offset, 8, this.length)
      return ieee754.read(this, offset, true, 52, 8)
    }

    Buffer.prototype.readDoubleBE = function readDoubleBE (offset, noAssert) {
      if (!noAssert) checkOffset(offset, 8, this.length)
      return ieee754.read(this, offset, false, 52, 8)
    }

    function checkInt (buf, value, offset, ext, max, min) {
      if (!Buffer.isBuffer(buf)) throw new TypeError('buffer must be a Buffer instance')
      if (value > max || value < min) throw new RangeError('value is out of bounds')
      if (offset + ext > buf.length) throw new RangeError('index out of range')
    }

    Buffer.prototype.writeUIntLE = function writeUIntLE (value, offset, byteLength, noAssert) {
      value = +value
      offset = offset | 0
      byteLength = byteLength | 0
      if (!noAssert) checkInt(this, value, offset, byteLength, Math.pow(2, 8 * byteLength), 0)

      var mul = 1
      var i = 0
      this[offset] = value & 0xFF
      while (++i < byteLength && (mul *= 0x100)) {
        this[offset + i] = (value / mul) & 0xFF
      }

      return offset + byteLength
    }

    Buffer.prototype.writeUIntBE = function writeUIntBE (value, offset, byteLength, noAssert) {
      value = +value
      offset = offset | 0
      byteLength = byteLength | 0
      if (!noAssert) checkInt(this, value, offset, byteLength, Math.pow(2, 8 * byteLength), 0)

      var i = byteLength - 1
      var mul = 1
      this[offset + i] = value & 0xFF
      while (--i >= 0 && (mul *= 0x100)) {
        this[offset + i] = (value / mul) & 0xFF
      }

      return offset + byteLength
    }

    Buffer.prototype.writeUInt8 = function writeUInt8 (value, offset, noAssert) {
      value = +value
      offset = offset | 0
      if (!noAssert) checkInt(this, value, offset, 1, 0xff, 0)
      if (!Buffer.TYPED_ARRAY_SUPPORT) value = Math.floor(value)
      this[offset] = (value & 0xff)
      return offset + 1
    }

    function objectWriteUInt16 (buf, value, offset, littleEndian) {
      if (value < 0) value = 0xffff + value + 1
      for (var i = 0, j = Math.min(buf.length - offset, 2); i < j; i++) {
        buf[offset + i] = (value & (0xff << (8 * (littleEndian ? i : 1 - i)))) >>>
          (littleEndian ? i : 1 - i) * 8
      }
    }

    Buffer.prototype.writeUInt16LE = function writeUInt16LE (value, offset, noAssert) {
      value = +value
      offset = offset | 0
      if (!noAssert) checkInt(this, value, offset, 2, 0xffff, 0)
      if (Buffer.TYPED_ARRAY_SUPPORT) {
        this[offset] = (value & 0xff)
        this[offset + 1] = (value >>> 8)
      } else {
        objectWriteUInt16(this, value, offset, true)
      }
      return offset + 2
    }

    Buffer.prototype.writeUInt16BE = function writeUInt16BE (value, offset, noAssert) {
      value = +value
      offset = offset | 0
      if (!noAssert) checkInt(this, value, offset, 2, 0xffff, 0)
      if (Buffer.TYPED_ARRAY_SUPPORT) {
        this[offset] = (value >>> 8)
        this[offset + 1] = (value & 0xff)
      } else {
        objectWriteUInt16(this, value, offset, false)
      }
      return offset + 2
    }

    function objectWriteUInt32 (buf, value, offset, littleEndian) {
      if (value < 0) value = 0xffffffff + value + 1
      for (var i = 0, j = Math.min(buf.length - offset, 4); i < j; i++) {
        buf[offset + i] = (value >>> (littleEndian ? i : 3 - i) * 8) & 0xff
      }
    }

    Buffer.prototype.writeUInt32LE = function writeUInt32LE (value, offset, noAssert) {
      value = +value
      offset = offset | 0
      if (!noAssert) checkInt(this, value, offset, 4, 0xffffffff, 0)
      if (Buffer.TYPED_ARRAY_SUPPORT) {
        this[offset + 3] = (value >>> 24)
        this[offset + 2] = (value >>> 16)
        this[offset + 1] = (value >>> 8)
        this[offset] = (value & 0xff)
      } else {
        objectWriteUInt32(this, value, offset, true)
      }
      return offset + 4
    }

    Buffer.prototype.writeUInt32BE = function writeUInt32BE (value, offset, noAssert) {
      value = +value
      offset = offset | 0
      if (!noAssert) checkInt(this, value, offset, 4, 0xffffffff, 0)
      if (Buffer.TYPED_ARRAY_SUPPORT) {
        this[offset] = (value >>> 24)
        this[offset + 1] = (value >>> 16)
        this[offset + 2] = (value >>> 8)
        this[offset + 3] = (value & 0xff)
      } else {
        objectWriteUInt32(this, value, offset, false)
      }
      return offset + 4
    }

    Buffer.prototype.writeIntLE = function writeIntLE (value, offset, byteLength, noAssert) {
      value = +value
      offset = offset | 0
      if (!noAssert) {
        var limit = Math.pow(2, 8 * byteLength - 1)

        checkInt(this, value, offset, byteLength, limit - 1, -limit)
      }

      var i = 0
      var mul = 1
      var sub = value < 0 ? 1 : 0
      this[offset] = value & 0xFF
      while (++i < byteLength && (mul *= 0x100)) {
        this[offset + i] = ((value / mul) >> 0) - sub & 0xFF
      }

      return offset + byteLength
    }

    Buffer.prototype.writeIntBE = function writeIntBE (value, offset, byteLength, noAssert) {
      value = +value
      offset = offset | 0
      if (!noAssert) {
        var limit = Math.pow(2, 8 * byteLength - 1)

        checkInt(this, value, offset, byteLength, limit - 1, -limit)
      }

      var i = byteLength - 1
      var mul = 1
      var sub = value < 0 ? 1 : 0
      this[offset + i] = value & 0xFF
      while (--i >= 0 && (mul *= 0x100)) {
        this[offset + i] = ((value / mul) >> 0) - sub & 0xFF
      }

      return offset + byteLength
    }

    Buffer.prototype.writeInt8 = function writeInt8 (value, offset, noAssert) {
      value = +value
      offset = offset | 0
      if (!noAssert) checkInt(this, value, offset, 1, 0x7f, -0x80)
      if (!Buffer.TYPED_ARRAY_SUPPORT) value = Math.floor(value)
      if (value < 0) value = 0xff + value + 1
      this[offset] = (value & 0xff)
      return offset + 1
    }

    Buffer.prototype.writeInt16LE = function writeInt16LE (value, offset, noAssert) {
      value = +value
      offset = offset | 0
      if (!noAssert) checkInt(this, value, offset, 2, 0x7fff, -0x8000)
      if (Buffer.TYPED_ARRAY_SUPPORT) {
        this[offset] = (value & 0xff)
        this[offset + 1] = (value >>> 8)
      } else {
        objectWriteUInt16(this, value, offset, true)
      }
      return offset + 2
    }

    Buffer.prototype.writeInt16BE = function writeInt16BE (value, offset, noAssert) {
      value = +value
      offset = offset | 0
      if (!noAssert) checkInt(this, value, offset, 2, 0x7fff, -0x8000)
      if (Buffer.TYPED_ARRAY_SUPPORT) {
        this[offset] = (value >>> 8)
        this[offset + 1] = (value & 0xff)
      } else {
        objectWriteUInt16(this, value, offset, false)
      }
      return offset + 2
    }

    Buffer.prototype.writeInt32LE = function writeInt32LE (value, offset, noAssert) {
      value = +value
      offset = offset | 0
      if (!noAssert) checkInt(this, value, offset, 4, 0x7fffffff, -0x80000000)
      if (Buffer.TYPED_ARRAY_SUPPORT) {
        this[offset] = (value & 0xff)
        this[offset + 1] = (value >>> 8)
        this[offset + 2] = (value >>> 16)
        this[offset + 3] = (value >>> 24)
      } else {
        objectWriteUInt32(this, value, offset, true)
      }
      return offset + 4
    }

    Buffer.prototype.writeInt32BE = function writeInt32BE (value, offset, noAssert) {
      value = +value
      offset = offset | 0
      if (!noAssert) checkInt(this, value, offset, 4, 0x7fffffff, -0x80000000)
      if (value < 0) value = 0xffffffff + value + 1
      if (Buffer.TYPED_ARRAY_SUPPORT) {
        this[offset] = (value >>> 24)
        this[offset + 1] = (value >>> 16)
        this[offset + 2] = (value >>> 8)
        this[offset + 3] = (value & 0xff)
      } else {
        objectWriteUInt32(this, value, offset, false)
      }
      return offset + 4
    }

    function checkIEEE754 (buf, value, offset, ext, max, min) {
      if (value > max || value < min) throw new RangeError('value is out of bounds')
      if (offset + ext > buf.length) throw new RangeError('index out of range')
      if (offset < 0) throw new RangeError('index out of range')
    }

    function writeFloat (buf, value, offset, littleEndian, noAssert) {
      if (!noAssert) {
        checkIEEE754(buf, value, offset, 4, 3.4028234663852886e+38, -3.4028234663852886e+38)
      }
      ieee754.write(buf, value, offset, littleEndian, 23, 4)
      return offset + 4
    }

    Buffer.prototype.writeFloatLE = function writeFloatLE (value, offset, noAssert) {
      return writeFloat(this, value, offset, true, noAssert)
    }

    Buffer.prototype.writeFloatBE = function writeFloatBE (value, offset, noAssert) {
      return writeFloat(this, value, offset, false, noAssert)
    }

    function writeDouble (buf, value, offset, littleEndian, noAssert) {
      if (!noAssert) {
        checkIEEE754(buf, value, offset, 8, 1.7976931348623157E+308, -1.7976931348623157E+308)
      }
      ieee754.write(buf, value, offset, littleEndian, 52, 8)
      return offset + 8
    }

    Buffer.prototype.writeDoubleLE = function writeDoubleLE (value, offset, noAssert) {
      return writeDouble(this, value, offset, true, noAssert)
    }

    Buffer.prototype.writeDoubleBE = function writeDoubleBE (value, offset, noAssert) {
      return writeDouble(this, value, offset, false, noAssert)
    }

// copy(targetBuffer, targetStart=0, sourceStart=0, sourceEnd=buffer.length)
    Buffer.prototype.copy = function copy (target, targetStart, start, end) {
      if (!start) start = 0
      if (!end && end !== 0) end = this.length
      if (targetStart >= target.length) targetStart = target.length
      if (!targetStart) targetStart = 0
      if (end > 0 && end < start) end = start

      // Copy 0 bytes; we're done
      if (end === start) return 0
      if (target.length === 0 || this.length === 0) return 0

      // Fatal error conditions
      if (targetStart < 0) {
        throw new RangeError('targetStart out of bounds')
      }
      if (start < 0 || start >= this.length) throw new RangeError('sourceStart out of bounds')
      if (end < 0) throw new RangeError('sourceEnd out of bounds')

      // Are we oob?
      if (end > this.length) end = this.length
      if (target.length - targetStart < end - start) {
        end = target.length - targetStart + start
      }

      var len = end - start
      var i

      if (this === target && start < targetStart && targetStart < end) {
        // descending copy from end
        for (i = len - 1; i >= 0; i--) {
          target[i + targetStart] = this[i + start]
        }
      } else if (len < 1000 || !Buffer.TYPED_ARRAY_SUPPORT) {
        // ascending copy from start
        for (i = 0; i < len; i++) {
          target[i + targetStart] = this[i + start]
        }
      } else {
        target._set(this.subarray(start, start + len), targetStart)
      }

      return len
    }

// fill(value, start=0, end=buffer.length)
    Buffer.prototype.fill = function fill (value, start, end) {
      if (!value) value = 0
      if (!start) start = 0
      if (!end) end = this.length

      if (end < start) throw new RangeError('end < start')

      // Fill 0 bytes; we're done
      if (end === start) return
      if (this.length === 0) return

      if (start < 0 || start >= this.length) throw new RangeError('start out of bounds')
      if (end < 0 || end > this.length) throw new RangeError('end out of bounds')

      var i
      if (typeof value === 'number') {
        for (i = start; i < end; i++) {
          this[i] = value
        }
      } else {
        var bytes = utf8ToBytes(value.toString())
        var len = bytes.length
        for (i = start; i < end; i++) {
          this[i] = bytes[i % len]
        }
      }

      return this
    }

    /**
     * Creates a new `ArrayBuffer` with the *copied* memory of the buffer instance.
     * Added in Node 0.12. Only available in browsers that support ArrayBuffer.
     */
    Buffer.prototype.toArrayBuffer = function toArrayBuffer () {
      if (typeof Uint8Array !== 'undefined') {
        if (Buffer.TYPED_ARRAY_SUPPORT) {
          return (new Buffer(this)).buffer
        } else {
          var buf = new Uint8Array(this.length)
          for (var i = 0, len = buf.length; i < len; i += 1) {
            buf[i] = this[i]
          }
          return buf.buffer
        }
      } else {
        throw new TypeError('Buffer.toArrayBuffer not supported in this browser')
      }
    }

// HELPER FUNCTIONS
// ================

    var BP = Buffer.prototype

    /**
     * Augment a Uint8Array *instance* (not the Uint8Array class!) with Buffer methods
     */
    Buffer._augment = function _augment (arr) {
      arr.constructor = Buffer
      arr._isBuffer = true

      // save reference to original Uint8Array set method before overwriting
      arr._set = arr.set

      // deprecated
      arr.get = BP.get
      arr.set = BP.set

      arr.write = BP.write
      arr.toString = BP.toString
      arr.toLocaleString = BP.toString
      arr.toJSON = BP.toJSON
      arr.equals = BP.equals
      arr.compare = BP.compare
      arr.indexOf = BP.indexOf
      arr.copy = BP.copy
      arr.slice = BP.slice
      arr.readUIntLE = BP.readUIntLE
      arr.readUIntBE = BP.readUIntBE
      arr.readUInt8 = BP.readUInt8
      arr.readUInt16LE = BP.readUInt16LE
      arr.readUInt16BE = BP.readUInt16BE
      arr.readUInt32LE = BP.readUInt32LE
      arr.readUInt32BE = BP.readUInt32BE
      arr.readIntLE = BP.readIntLE
      arr.readIntBE = BP.readIntBE
      arr.readInt8 = BP.readInt8
      arr.readInt16LE = BP.readInt16LE
      arr.readInt16BE = BP.readInt16BE
      arr.readInt32LE = BP.readInt32LE
      arr.readInt32BE = BP.readInt32BE
      arr.readFloatLE = BP.readFloatLE
      arr.readFloatBE = BP.readFloatBE
      arr.readDoubleLE = BP.readDoubleLE
      arr.readDoubleBE = BP.readDoubleBE
      arr.writeUInt8 = BP.writeUInt8
      arr.writeUIntLE = BP.writeUIntLE
      arr.writeUIntBE = BP.writeUIntBE
      arr.writeUInt16LE = BP.writeUInt16LE
      arr.writeUInt16BE = BP.writeUInt16BE
      arr.writeUInt32LE = BP.writeUInt32LE
      arr.writeUInt32BE = BP.writeUInt32BE
      arr.writeIntLE = BP.writeIntLE
      arr.writeIntBE = BP.writeIntBE
      arr.writeInt8 = BP.writeInt8
      arr.writeInt16LE = BP.writeInt16LE
      arr.writeInt16BE = BP.writeInt16BE
      arr.writeInt32LE = BP.writeInt32LE
      arr.writeInt32BE = BP.writeInt32BE
      arr.writeFloatLE = BP.writeFloatLE
      arr.writeFloatBE = BP.writeFloatBE
      arr.writeDoubleLE = BP.writeDoubleLE
      arr.writeDoubleBE = BP.writeDoubleBE
      arr.fill = BP.fill
      arr.inspect = BP.inspect
      arr.toArrayBuffer = BP.toArrayBuffer

      return arr
    }

    var INVALID_BASE64_RE = /[^+\/0-9A-Za-z-_]/g

    function base64clean (str) {
      // Node strips out invalid characters like \n and \t from the string, base64-js does not
      str = stringtrim(str).replace(INVALID_BASE64_RE, '')
      // Node converts strings with length < 2 to ''
      if (str.length < 2) return ''
      // Node allows for non-padded base64 strings (missing trailing ===), base64-js does not
      while (str.length % 4 !== 0) {
        str = str + '='
      }
      return str
    }

    function stringtrim (str) {
      if (str.trim) return str.trim()
      return str.replace(/^\s+|\s+$/g, '')
    }

    function toHex (n) {
      if (n < 16) return '0' + n.toString(16)
      return n.toString(16)
    }

    function utf8ToBytes (string, units) {
      units = units || Infinity
      var codePoint
      var length = string.length
      var leadSurrogate = null
      var bytes = []

      for (var i = 0; i < length; i++) {
        codePoint = string.charCodeAt(i)

        // is surrogate component
        if (codePoint > 0xD7FF && codePoint < 0xE000) {
          // last char was a lead
          if (!leadSurrogate) {
            // no lead yet
            if (codePoint > 0xDBFF) {
              // unexpected trail
              if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD)
              continue
            } else if (i + 1 === length) {
              // unpaired lead
              if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD)
              continue
            }

            // valid lead
            leadSurrogate = codePoint

            continue
          }

          // 2 leads in a row
          if (codePoint < 0xDC00) {
            if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD)
            leadSurrogate = codePoint
            continue
          }

          // valid surrogate pair
          codePoint = (leadSurrogate - 0xD800 << 10 | codePoint - 0xDC00) + 0x10000
        } else if (leadSurrogate) {
          // valid bmp char, but last char was a lead
          if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD)
        }

        leadSurrogate = null

        // encode utf8
        if (codePoint < 0x80) {
          if ((units -= 1) < 0) break
          bytes.push(codePoint)
        } else if (codePoint < 0x800) {
          if ((units -= 2) < 0) break
          bytes.push(
            codePoint >> 0x6 | 0xC0,
            codePoint & 0x3F | 0x80
          )
        } else if (codePoint < 0x10000) {
          if ((units -= 3) < 0) break
          bytes.push(
            codePoint >> 0xC | 0xE0,
            codePoint >> 0x6 & 0x3F | 0x80,
            codePoint & 0x3F | 0x80
          )
        } else if (codePoint < 0x110000) {
          if ((units -= 4) < 0) break
          bytes.push(
            codePoint >> 0x12 | 0xF0,
            codePoint >> 0xC & 0x3F | 0x80,
            codePoint >> 0x6 & 0x3F | 0x80,
            codePoint & 0x3F | 0x80
          )
        } else {
          throw new Error('Invalid code point')
        }
      }

      return bytes
    }

    function asciiToBytes (str) {
      var byteArray = []
      for (var i = 0; i < str.length; i++) {
        // Node's code seems to be doing this and not & 0x7F..
        byteArray.push(str.charCodeAt(i) & 0xFF)
      }
      return byteArray
    }

    function utf16leToBytes (str, units) {
      var c, hi, lo
      var byteArray = []
      for (var i = 0; i < str.length; i++) {
        if ((units -= 2) < 0) break

        c = str.charCodeAt(i)
        hi = c >> 8
        lo = c % 256
        byteArray.push(lo)
        byteArray.push(hi)
      }

      return byteArray
    }

    function base64ToBytes (str) {
      return base64.toByteArray(base64clean(str))
    }

    function blitBuffer (src, dst, offset, length) {
      for (var i = 0; i < length; i++) {
        if ((i + offset >= dst.length) || (i >= src.length)) break
        dst[i + offset] = src[i]
      }
      return i
    }

  }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
},{"base64-js":2,"ieee754":3,"isarray":4}],2:[function(require,module,exports){
  var lookup = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';

  ;(function (exports) {
    'use strict';

    var Arr = (typeof Uint8Array !== 'undefined')
      ? Uint8Array
      : Array

    var PLUS   = '+'.charCodeAt(0)
    var SLASH  = '/'.charCodeAt(0)
    var NUMBER = '0'.charCodeAt(0)
    var LOWER  = 'a'.charCodeAt(0)
    var UPPER  = 'A'.charCodeAt(0)
    var PLUS_URL_SAFE = '-'.charCodeAt(0)
    var SLASH_URL_SAFE = '_'.charCodeAt(0)

    function decode (elt) {
      var code = elt.charCodeAt(0)
      if (code === PLUS ||
        code === PLUS_URL_SAFE)
        return 62 // '+'
      if (code === SLASH ||
        code === SLASH_URL_SAFE)
        return 63 // '/'
      if (code < NUMBER)
        return -1 //no match
      if (code < NUMBER + 10)
        return code - NUMBER + 26 + 26
      if (code < UPPER + 26)
        return code - UPPER
      if (code < LOWER + 26)
        return code - LOWER + 26
    }

    function b64ToByteArray (b64) {
      var i, j, l, tmp, placeHolders, arr

      if (b64.length % 4 > 0) {
        throw new Error('Invalid string. Length must be a multiple of 4')
      }

      // the number of equal signs (place holders)
      // if there are two placeholders, than the two characters before it
      // represent one byte
      // if there is only one, then the three characters before it represent 2 bytes
      // this is just a cheap hack to not do indexOf twice
      var len = b64.length
      placeHolders = '=' === b64.charAt(len - 2) ? 2 : '=' === b64.charAt(len - 1) ? 1 : 0

      // base64 is 4/3 + up to two characters of the original data
      arr = new Arr(b64.length * 3 / 4 - placeHolders)

      // if there are placeholders, only get up to the last complete 4 chars
      l = placeHolders > 0 ? b64.length - 4 : b64.length

      var L = 0

      function push (v) {
        arr[L++] = v
      }

      for (i = 0, j = 0; i < l; i += 4, j += 3) {
        tmp = (decode(b64.charAt(i)) << 18) | (decode(b64.charAt(i + 1)) << 12) | (decode(b64.charAt(i + 2)) << 6) | decode(b64.charAt(i + 3))
        push((tmp & 0xFF0000) >> 16)
        push((tmp & 0xFF00) >> 8)
        push(tmp & 0xFF)
      }

      if (placeHolders === 2) {
        tmp = (decode(b64.charAt(i)) << 2) | (decode(b64.charAt(i + 1)) >> 4)
        push(tmp & 0xFF)
      } else if (placeHolders === 1) {
        tmp = (decode(b64.charAt(i)) << 10) | (decode(b64.charAt(i + 1)) << 4) | (decode(b64.charAt(i + 2)) >> 2)
        push((tmp >> 8) & 0xFF)
        push(tmp & 0xFF)
      }

      return arr
    }

    function uint8ToBase64 (uint8) {
      var i,
        extraBytes = uint8.length % 3, // if we have 1 byte left, pad 2 bytes
        output = "",
        temp, length

      function encode (num) {
        return lookup.charAt(num)
      }

      function tripletToBase64 (num) {
        return encode(num >> 18 & 0x3F) + encode(num >> 12 & 0x3F) + encode(num >> 6 & 0x3F) + encode(num & 0x3F)
      }

      // go through the array every three bytes, we'll deal with trailing stuff later
      for (i = 0, length = uint8.length - extraBytes; i < length; i += 3) {
        temp = (uint8[i] << 16) + (uint8[i + 1] << 8) + (uint8[i + 2])
        output += tripletToBase64(temp)
      }

      // pad the end with zeros, but make sure to not forget the extra bytes
      switch (extraBytes) {
        case 1:
          temp = uint8[uint8.length - 1]
          output += encode(temp >> 2)
          output += encode((temp << 4) & 0x3F)
          output += '=='
          break
        case 2:
          temp = (uint8[uint8.length - 2] << 8) + (uint8[uint8.length - 1])
          output += encode(temp >> 10)
          output += encode((temp >> 4) & 0x3F)
          output += encode((temp << 2) & 0x3F)
          output += '='
          break
      }

      return output
    }

    exports.toByteArray = b64ToByteArray
    exports.fromByteArray = uint8ToBase64
  }(typeof exports === 'undefined' ? (this.base64js = {}) : exports))

},{}],3:[function(require,module,exports){
  exports.read = function (buffer, offset, isLE, mLen, nBytes) {
    var e, m
    var eLen = nBytes * 8 - mLen - 1
    var eMax = (1 << eLen) - 1
    var eBias = eMax >> 1
    var nBits = -7
    var i = isLE ? (nBytes - 1) : 0
    var d = isLE ? -1 : 1
    var s = buffer[offset + i]

    i += d

    e = s & ((1 << (-nBits)) - 1)
    s >>= (-nBits)
    nBits += eLen
    for (; nBits > 0; e = e * 256 + buffer[offset + i], i += d, nBits -= 8) {}

    m = e & ((1 << (-nBits)) - 1)
    e >>= (-nBits)
    nBits += mLen
    for (; nBits > 0; m = m * 256 + buffer[offset + i], i += d, nBits -= 8) {}

    if (e === 0) {
      e = 1 - eBias
    } else if (e === eMax) {
      return m ? NaN : ((s ? -1 : 1) * Infinity)
    } else {
      m = m + Math.pow(2, mLen)
      e = e - eBias
    }
    return (s ? -1 : 1) * m * Math.pow(2, e - mLen)
  }

  exports.write = function (buffer, value, offset, isLE, mLen, nBytes) {
    var e, m, c
    var eLen = nBytes * 8 - mLen - 1
    var eMax = (1 << eLen) - 1
    var eBias = eMax >> 1
    var rt = (mLen === 23 ? Math.pow(2, -24) - Math.pow(2, -77) : 0)
    var i = isLE ? 0 : (nBytes - 1)
    var d = isLE ? 1 : -1
    var s = value < 0 || (value === 0 && 1 / value < 0) ? 1 : 0

    value = Math.abs(value)

    if (isNaN(value) || value === Infinity) {
      m = isNaN(value) ? 1 : 0
      e = eMax
    } else {
      e = Math.floor(Math.log(value) / Math.LN2)
      if (value * (c = Math.pow(2, -e)) < 1) {
        e--
        c *= 2
      }
      if (e + eBias >= 1) {
        value += rt / c
      } else {
        value += rt * Math.pow(2, 1 - eBias)
      }
      if (value * c >= 2) {
        e++
        c /= 2
      }

      if (e + eBias >= eMax) {
        m = 0
        e = eMax
      } else if (e + eBias >= 1) {
        m = (value * c - 1) * Math.pow(2, mLen)
        e = e + eBias
      } else {
        m = value * Math.pow(2, eBias - 1) * Math.pow(2, mLen)
        e = 0
      }
    }

    for (; mLen >= 8; buffer[offset + i] = m & 0xff, i += d, m /= 256, mLen -= 8) {}

    e = (e << mLen) | m
    eLen += mLen
    for (; eLen > 0; buffer[offset + i] = e & 0xff, i += d, e /= 256, eLen -= 8) {}

    buffer[offset + i - d] |= s * 128
  }

},{}],4:[function(require,module,exports){
  var toString = {}.toString;

  module.exports = Array.isArray || function (arr) {
      return toString.call(arr) == '[object Array]';
    };

},{}],5:[function(require,module,exports){
// shim for using process in browser

  var process = module.exports = {};
  var queue = [];
  var draining = false;
  var currentQueue;
  var queueIndex = -1;

  function cleanUpNextTick() {
    draining = false;
    if (currentQueue.length) {
      queue = currentQueue.concat(queue);
    } else {
      queueIndex = -1;
    }
    if (queue.length) {
      drainQueue();
    }
  }

  function drainQueue() {
    if (draining) {
      return;
    }
    var timeout = setTimeout(cleanUpNextTick);
    draining = true;

    var len = queue.length;
    while(len) {
      currentQueue = queue;
      queue = [];
      while (++queueIndex < len) {
        if (currentQueue) {
          currentQueue[queueIndex].run();
        }
      }
      queueIndex = -1;
      len = queue.length;
    }
    currentQueue = null;
    draining = false;
    clearTimeout(timeout);
  }

  process.nextTick = function (fun) {
    var args = new Array(arguments.length - 1);
    if (arguments.length > 1) {
      for (var i = 1; i < arguments.length; i++) {
        args[i - 1] = arguments[i];
      }
    }
    queue.push(new Item(fun, args));
    if (queue.length === 1 && !draining) {
      setTimeout(drainQueue, 0);
    }
  };

// v8 likes predictible objects
  function Item(fun, array) {
    this.fun = fun;
    this.array = array;
  }
  Item.prototype.run = function () {
    this.fun.apply(null, this.array);
  };
  process.title = 'browser';
  process.browser = true;
  process.env = {};
  process.argv = [];
  process.version = ''; // empty string to avoid regexp issues
  process.versions = {};

  function noop() {}

  process.on = noop;
  process.addListener = noop;
  process.once = noop;
  process.off = noop;
  process.removeListener = noop;
  process.removeAllListeners = noop;
  process.emit = noop;

  process.binding = function (name) {
    throw new Error('process.binding is not supported');
  };

  process.cwd = function () { return '/' };
  process.chdir = function (dir) {
    throw new Error('process.chdir is not supported');
  };
  process.umask = function() { return 0; };

},{}],6:[function(require,module,exports){
  /**
   * Node.js module for Forge.
   *
   * @author Dave Longley
   *
   * Copyright 2011-2014 Digital Bazaar, Inc.
   */
  (function() {
    var name = 'forge';
    if(typeof define !== 'function') {
      // NodeJS -> AMD
      if(typeof module === 'object' && module.exports) {
        var nodeJS = true;
        define = function(ids, factory) {
          factory(require, module);
        };
      } else {
        // <script>
        if(typeof forge === 'undefined') {
          // set to true to disable native code if even it's available
          forge = {disableNativeCode: false};
        }
        return;
      }
    }
// AMD
    var deps;
    var defineFunc = function(require, module) {
      module.exports = function(forge) {
        var mods = deps.map(function(dep) {
          return require(dep);
        });
        // handle circular dependencies
        forge = forge || {};
        forge.defined = forge.defined || {};
        if(forge.defined[name]) {
          return forge[name];
        }
        forge.defined[name] = true;
        for(var i = 0; i < mods.length; ++i) {
          mods[i](forge);
        }
        return forge;
      };
      // set to true to disable native code if even it's available
      module.exports.disableNativeCode = false;
      module.exports(module.exports);
    };
    var tmpDefine = define;
    define = function(ids, factory) {
      deps = (typeof ids === 'string') ? factory.slice(2) : ids.slice(2);
      if(nodeJS) {
        delete define;
        return tmpDefine.apply(null, Array.prototype.slice.call(arguments, 0));
      }
      define = tmpDefine;
      return define.apply(null, Array.prototype.slice.call(arguments, 0));
    };
    define([
      'require',
      'module',
      './aes',
      './aesCipherSuites',
      './asn1',
      './cipher',
      './cipherModes',
      './debug',
      './des',
      './hmac',
      './kem',
      './log',
      './md',
      './mgf1',
      './pbkdf2',
      './pem',
      './pkcs7',
      './pkcs1',
      './pkcs12',
      './pki',
      './prime',
      './prng',
      './pss',
      './random',
      './rc2',
      './ssh',
      './task',
      './tls',
      './util'
    ], function() {
      defineFunc.apply(null, Array.prototype.slice.call(arguments, 0));
    });
  })();

},{}],7:[function(require,module,exports){
  (function (global){
    "use strict";
    var _ = (typeof window !== "undefined" ? window['_'] : typeof global !== "undefined" ? global['_'] : null);
    var util = require('../util');

    /**
     *
     * @param {Object} config
     * @param {Number} config.x X offset in EMU's
     * @param {Number} config.y Y offset in EMU's
     * @param {Number} config.width Width in EMU's
     * @param {Number} config.height Height in EMU's
     * @constructor
     */
    var AbsoluteAnchor = function (config) {
      this.x = null;
      this.y = null;
      this.width = null;
      this.height = null;
      if(config) {
        this.setPos(config.x, config.y);
        this.setDimensions(config.width, config.height);
      }
    };
    _.extend(AbsoluteAnchor.prototype, {
      /**
       * Sets the X and Y offsets.
       *
       * @param {Number} x
       * @param {Number} y
       * @returns {undefined}
       */
      setPos: function (x, y) {
        this.x = x;
        this.y = y;
      },
      /**
       * Sets the width and height of the image.
       *
       * @param {Number} width
       * @param {Number} height
       * @returns {undefined}
       */
      setDimensions: function (width, height) {
        this.width = width;
        this.height = height;
      },
      toXML: function (xmlDoc, content) {
        var root = util.createElement(xmlDoc, 'xdr:absoluteAnchor');
        var pos = util.createElement(xmlDoc, 'xdr:pos');
        pos.setAttribute('x', this.x);
        pos.setAttribute('y', this.y);
        root.appendChild(pos);

        var dimensions = util.createElement(xmlDoc, 'xdr:ext');
        dimensions.setAttribute('cx', this.width);
        dimensions.setAttribute('cy', this.height);
        root.appendChild(dimensions);

        root.appendChild(content);

        root.appendChild(util.createElement(xmlDoc, 'xdr:clientData'));
        return root;
      }
    });
    module.exports = AbsoluteAnchor;
  }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
},{"../util":28}],8:[function(require,module,exports){
  (function (global){
    "use strict";
    var _ = (typeof window !== "undefined" ? window['_'] : typeof global !== "undefined" ? global['_'] : null);
//var util = require('../util');
    var Chart = function () {

    };
    _.extend(Chart.prototype, {

    });
    module.exports = Chart;
  }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
},{}],9:[function(require,module,exports){
  (function (global){
    "use strict";
    var _ = (typeof window !== "undefined" ? window['_'] : typeof global !== "undefined" ? global['_'] : null);
    var util = require('../util');

    /**
     *
     * @param {Object} config
     * @param {Number} config.x The cell column number that the top left of the picture will start in
     * @param {Number} config.y The cell row number that the top left of the picture will start in
     * @param {Number} config.width Width in EMU's
     * @param {Number} config.height Height in EMU's
     * @constructor
     */
    var OneCellAnchor = function (config) {
      this.x = null;
      this.y = null;
      this.xOff = null;
      this.yOff = null;
      this.width = null;
      this.height = null;
      if(config) {
        this.setPos(config.x, config.y, config.xOff, config.yOff);
        this.setDimensions(config.width, config.height);
      }
    };
    _.extend(OneCellAnchor.prototype, {
      setPos: function (x, y, xOff, yOff) {
        this.x = x;
        this.y = y;
        if(xOff !== undefined) {
          this.xOff = xOff;
        }
        if(yOff !== undefined) {
          this.yOff = yOff;
        }
      },
      setDimensions: function (width, height) {
        this.width = width;
        this.height = height;
      },
      toXML: function (xmlDoc, content) {
        var root = util.createElement(xmlDoc, 'xdr:oneCellAnchor');
        var from = util.createElement(xmlDoc, 'xdr:from');
        var fromCol = util.createElement(xmlDoc, 'xdr:col');
        fromCol.appendChild(xmlDoc.createTextNode(this.x));
        var fromColOff = util.createElement(xmlDoc, 'xdr:colOff');
        fromColOff.appendChild(xmlDoc.createTextNode(this.xOff || 0));
        var fromRow = util.createElement(xmlDoc, 'xdr:row');
        fromRow.appendChild(xmlDoc.createTextNode(this.y));
        var fromRowOff = util.createElement(xmlDoc, 'xdr:rowOff');
        fromRowOff.appendChild(xmlDoc.createTextNode(this.yOff || 0));
        from.appendChild(fromCol);
        from.appendChild(fromColOff);
        from.appendChild(fromRow);
        from.appendChild(fromRowOff);

        root.appendChild(from);

        var dimensions = util.createElement(xmlDoc, 'xdr:ext');
        dimensions.setAttribute('cx', this.width);
        dimensions.setAttribute('cy', this.height);
        root.appendChild(dimensions);

        root.appendChild(content);

        root.appendChild(util.createElement(xmlDoc, 'xdr:clientData'));
        return root;
      }
    });
    module.exports = OneCellAnchor;
  }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
},{"../util":28}],10:[function(require,module,exports){
  (function (global){
    "use strict";
    var _ = (typeof window !== "undefined" ? window['_'] : typeof global !== "undefined" ? global['_'] : null);
    var util = require('../util');
    var Drawing = require('./index');

    var Picture = function () {
      this.media = null;
      this.id = _.uniqueId('Picture');
      this.pictureId = util.uniqueId('Picture');
      this.fill = {};
      this.mediaData = null;
    };

    Picture.prototype = new Drawing();

    _.extend(Picture.prototype, {
      setMedia: function (mediaRef) {
        this.mediaData = mediaRef;
      },
      setDescription: function (description) {
        this.description = description;
      },
      setFillType: function (type) {
        this.fill.type = type;
      },
      setFillConfig: function (config) {
        _.extend(this.fill, config);
      },
      getMediaType: function () {
        return 'image';
      },
      getMediaData: function () {
        return this.mediaData;
      },
      setRelationshipId: function (rId) {
        this.mediaData.rId = rId;
      },
      toXML: function (xmlDoc) {
        var pictureNode = util.createElement(xmlDoc, 'xdr:pic');

        var nonVisibleProperties = util.createElement(xmlDoc, 'xdr:nvPicPr');

        var nameProperties = util.createElement(xmlDoc, 'xdr:cNvPr', [
          ['id', this.pictureId],
          ['name', this.mediaData.fileName],
          ['descr', this.description || ""]
        ]);
        nonVisibleProperties.appendChild(nameProperties);
        var nvPicProperties = util.createElement(xmlDoc, 'xdr:cNvPicPr');
        nvPicProperties.appendChild(util.createElement(xmlDoc, 'a:picLocks', [
          ['noChangeAspect', '1'],
          ['noChangeArrowheads', '1']
        ]));
        nonVisibleProperties.appendChild(nvPicProperties);
        pictureNode.appendChild(nonVisibleProperties);
        var pictureFill = util.createElement(xmlDoc, 'xdr:blipFill');
        pictureFill.appendChild(util.createElement(xmlDoc, 'a:blip', [
          ['xmlns:r', util.schemas.relationships],
          ['r:embed', this.mediaData.rId]
        ]));
        pictureFill.appendChild(util.createElement(xmlDoc, 'a:srcRect'));
        var stretch = util.createElement(xmlDoc, 'a:stretch');
        stretch.appendChild(util.createElement(xmlDoc, 'a:fillRect'));
        pictureFill.appendChild(stretch);
        pictureNode.appendChild(pictureFill);

        var shapeProperties = util.createElement(xmlDoc, 'xdr:spPr', [
          ['bwMode', 'auto']
        ]);

        var transform2d = util.createElement(xmlDoc, 'a:xfrm');
        shapeProperties.appendChild(transform2d);

        var presetGeometry = util.createElement(xmlDoc, 'a:prstGeom', [
          ['prst', 'rect']
        ]);
        shapeProperties.appendChild(presetGeometry);



        pictureNode.appendChild(shapeProperties);
//            <xdr:spPr bwMode="auto">
//                <a:xfrm>
//                    <a:off x="1" y="1"/>
//                    <a:ext cx="1640253" cy="1885949"/>
//                </a:xfrm>
//                <a:prstGeom prst="rect">
//                    <a:avLst/>
//                </a:prstGeom>
//                <a:noFill/>
//                <a:extLst>
//                    <a:ext uri="{909E8E84-426E-40DD-AFC4-6F175D3DCCD1}">
//                        <a14:hiddenFill xmlns:a14="http://schemas.microsoft.com/office/drawing/2010/main">
//                            <a:solidFill>
//                                <a:srgbClr val="FFFFFF"/>
//                            </a:solidFill>
//                        </a14:hiddenFill>
//                    </a:ext>
//                </a:extLst>
//            </xdr:spPr>
//
        return this.anchor.toXML(xmlDoc, pictureNode);
      }
    });

    module.exports = Picture;

  }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
},{"../util":28,"./index":12}],11:[function(require,module,exports){
  (function (global){
    "use strict";
    var _ = (typeof window !== "undefined" ? window['_'] : typeof global !== "undefined" ? global['_'] : null);
    var util = require('../util');

    var TwoCellAnchor = function (config) {
      this.from = {xOff: 0, yOff: 0};
      this.to = {xOff: 0, yOff: 0};
      if(config) {
        this.setFrom(config.from.x, config.from.y, config.to.xOff, config.to.yOff);
        this.setTo(config.to.x, config.to.y, config.to.xOff, config.to.yOff);
      }
    };
    _.extend(TwoCellAnchor.prototype, {
      setFrom: function (x, y, xOff, yOff) {
        this.from.x = x;
        this.from.y = y;
        if(xOff !== undefined) {
          this.from.xOff = xOff;
        }
        if(yOff !== undefined) {
          this.from.yOff = xOff;
        }
      },
      setTo: function (x, y, xOff, yOff) {
        this.to.x = x;
        this.to.y = y;
        if(xOff !== undefined) {
          this.to.xOff = xOff;
        }
        if(yOff !== undefined) {
          this.to.yOff = xOff;
        }
      },
      toXML: function (xmlDoc, content) {
        var root = util.createElement(xmlDoc, 'xdr:twoCellAnchor');

        var from = util.createElement(xmlDoc, 'xdr:from');
        var fromCol = util.createElement(xmlDoc, 'xdr:col');
        fromCol.appendChild(xmlDoc.createTextNode(this.from.x));
        var fromColOff = util.createElement(xmlDoc, 'xdr:colOff');
        fromColOff.appendChild(xmlDoc.createTextNode(this.from.xOff));
        var fromRow = util.createElement(xmlDoc, 'xdr:row');
        fromRow.appendChild(xmlDoc.createTextNode(this.from.y));
        var fromRowOff = util.createElement(xmlDoc, 'xdr:rowOff');
        fromRowOff.appendChild(xmlDoc.createTextNode(this.from.yOff));

        from.appendChild(fromCol);
        from.appendChild(fromColOff);
        from.appendChild(fromRow);
        from.appendChild(fromRowOff);

        var to = util.createElement(xmlDoc, 'xdr:to');
        var toCol = util.createElement(xmlDoc, 'xdr:col');
        toCol.appendChild(xmlDoc.createTextNode(this.to.x));
        var toColOff = util.createElement(xmlDoc, 'xdr:colOff');
        toColOff.appendChild(xmlDoc.createTextNode(this.from.xOff));
        var toRow = util.createElement(xmlDoc, 'xdr:row');
        toRow.appendChild(xmlDoc.createTextNode(this.to.y));
        var toRowOff = util.createElement(xmlDoc, 'xdr:rowOff');
        toRowOff.appendChild(xmlDoc.createTextNode(this.from.yOff));

        to.appendChild(toCol);
        to.appendChild(toColOff);
        to.appendChild(toRow);
        to.appendChild(toRowOff);


        root.appendChild(from);
        root.appendChild(to);

        root.appendChild(content);

        root.appendChild(util.createElement(xmlDoc, 'xdr:clientData'));
        return root;
      }
    });
    module.exports = TwoCellAnchor;

  }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
},{"../util":28}],12:[function(require,module,exports){
  (function (global){
    "use strict";
    var _ = (typeof window !== "undefined" ? window['_'] : typeof global !== "undefined" ? global['_'] : null);
    var AbsoluteAnchor = require('./AbsoluteAnchor');
    var OneCellAnchor = require('./OneCellAnchor');
    var TwoCellAnchor = require('./TwoCellAnchor');

    /**
     * This is mostly a global spot where all of the relationship managers can get and set
     * path information from/to.
     * @module Excel/Drawing
     */
    var Drawing = function () {
      this.id = _.uniqueId('Drawing');
    };

    _.extend(Drawing.prototype, {
      /**
       *
       * @param {String} type Can be 'absoluteAnchor', 'oneCellAnchor', or 'twoCellAnchor'.
       * @param {Object} config Shorthand - pass the created anchor coords that can normally be used to construct it.
       * @returns {Anchor}
       */
      createAnchor: function (type, config) {
        config = config || {};
        config.drawing = this;
        switch(type) {
          case 'absoluteAnchor':
            this.anchor = new AbsoluteAnchor(config);
            break;
          case 'oneCellAnchor':
            this.anchor = new OneCellAnchor(config);
            break;
          case 'twoCellAnchor':
            this.anchor = new TwoCellAnchor(config);
            break;
        }
        return this.anchor;
      }
    });

    Object.defineProperties(Drawing, {
      AbsoluteAnchor: {get: function () { return require('./AbsoluteAnchor'); }},
      Chart: {get: function () { return require('./Chart'); }},
      OneCellAnchor: {get: function () { return require('./OneCellAnchor'); }},
      Picture: {get: function () { return require('./Picture'); }},
      TwoCellAnchor: {get: function () { return require('./TwoCellAnchor'); }}
    });

    module.exports = Drawing;

  }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
},{"./AbsoluteAnchor":7,"./Chart":8,"./OneCellAnchor":9,"./Picture":10,"./TwoCellAnchor":11}],13:[function(require,module,exports){
  (function (global){
    /**
     * @module Excel/Drawings
     */
    "use strict";
    var _ = (typeof window !== "undefined" ? window['_'] : typeof global !== "undefined" ? global['_'] : null);
    var util = require('./util');
    var RelationshipManager = require('./RelationshipManager');

    var Drawings = function () {
      this.drawings = [];
      this.relations = new RelationshipManager();
      this.id = _.uniqueId('Drawings');
    };

    _.extend(Drawings.prototype, {
      /**
       * Adds a drawing (more likely a subclass of a Drawing) to the 'Drawings' for a particular worksheet.
       *
       * @param {Drawing} drawing
       * @returns {undefined}
       */
      addDrawing: function (drawing) {
        this.drawings.push(drawing);
      },
      getCount: function () {
        return this.drawings.length;
      },
      toXML: function () {
        var doc = util.createXmlDoc(util.schemas.spreadsheetDrawing, 'xdr:wsDr');
        var drawings = doc.documentElement;
        drawings.setAttribute('xmlns:a', util.schemas.drawing);
        drawings.setAttribute('xmlns:r', util.schemas.relationships);
        drawings.setAttribute('xmlns:xdr', util.schemas.spreadsheetDrawing);

        for(var i = 0, l = this.drawings.length; i < l; i++) {

          var rId = this.relations.getRelationshipId(this.drawings[i].getMediaData());
          if(!rId) {
            rId = this.relations.addRelation(this.drawings[i].getMediaData(), this.drawings[i].getMediaType()); //chart
          }
          this.drawings[i].setRelationshipId(rId);
          drawings.appendChild(this.drawings[i].toXML(doc));
        }
        return doc;
      }
    });

    module.exports = Drawings;
  }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
},{"./RelationshipManager":17,"./util":28}],14:[function(require,module,exports){
  (function (global){
    "use strict";

    /**
     * @module Excel/Pane
     *
     * https://msdn.microsoft.com/en-us/library/documentformat.openxml.spreadsheet.pane%28v=office.14%29.aspx
     */
    var _ = (typeof window !== "undefined" ? window['_'] : typeof global !== "undefined" ? global['_'] : null);

    var Pane = function () {

      /*
       Possible Values:
       null
       split	Split
       frozen	Frozen
       frozenSplit	Frozen Split
       http://www.datypic.com/sc/ooxml/t-ssml_ST_PaneState.html
       */
      this.state = null;
      this.xSplit = null;
      this.ySplit = null;
      this.activePane = 'bottomRight';
      this.topLeftCell = null;

    };

    _.extend(Pane.prototype, {

      freezePane: function(column, row, cell) {
        this._freezePane = {xSplit: column, ySplit: row, cell: cell};
      },

      exportXML: function (doc) {
        var pane = doc.createElement('pane');

        if(this.state !== null) {
          pane.setAttribute('xSplit', this._freezePane.xSplit);
          pane.setAttribute('ySplit', this._freezePane.ySplit);
          pane.setAttribute('topLeftCell', this._freezePane.cell);
          pane.setAttribute('activePane', 'bottomRight');
          pane.setAttribute('state', 'frozen');
        }
        return pane;
      }
    });

    module.exports = Pane;
  }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
},{}],15:[function(require,module,exports){
  /**
   * This is mostly a global spot where all of the relationship managers can get and set
   * path information from/to.
   * @module Excel/Paths
   */
  module.exports = {};
},{}],16:[function(require,module,exports){
  "use strict";

  module.exports = {
    /**
     * Converts pixel sizes to 'EMU's, which is what Open XML uses.
     *
     * @todo clean this up. Code borrowed from http://polymathprogrammer.com/2009/10/22/english-metric-units-and-open-xml/,
     * but not sure that it's going to be as accurate as it needs to be.
     *
     * @param int pixels
     * @returns int
     */
    pixelsToEMUs: function (pixels) {
      return Math.round(pixels * 914400 / 96);
    }
  };

},{}],17:[function(require,module,exports){
  (function (global){
    "use strict";
    var _ = (typeof window !== "undefined" ? window['_'] : typeof global !== "undefined" ? global['_'] : null);
    var util = require('./util');
    var Paths = require('./Paths');


    /**
     * @module Excel/RelationshipManager
     */
    var RelationshipManager = function () {
      this.relations = {};
      this.lastId = 1;
    };

    _.uniqueId('rId'); //priming

    _.extend(RelationshipManager.prototype, {

      importData: function (data) {
        this.relations = data.relations;
        this.lastId = data.lastId;
      },
      exportData: function () {
        return {
          relations: this.relations,
          lastId: this.lastId
        };
      },

      addRelation: function (object, type) {
        this.relations[object.id] = {
          id: _.uniqueId('rId'),
          schema: util.schemas[type],
          object: object
        };
        return this.relations[object.id].id;
      },

      getRelationshipId: function (object) {
        return this.relations[object.id] ? this.relations[object.id].id : null;
      },

      toXML: function () {
        var doc = util.createXmlDoc(util.schemas.relationshipPackage, 'Relationships');
        var relationships = doc.documentElement;

        _.each(this.relations, function (data, id) {
          var relationship = util.createElement(doc, 'Relationship', [
            ['Id', data.id],
            ['Type', data.schema],
            ['Target', data.object.target || Paths[id]]
          ]);
          data.object.targetMode && relationship.setAttribute('TargetMode', data.object.targetMode);
          relationships.appendChild(relationship);
        });
        return doc;
      }
    });

    module.exports = RelationshipManager;
  }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
},{"./Paths":15,"./util":28}],18:[function(require,module,exports){
  (function (global){
    "use strict";
    var _ = (typeof window !== "undefined" ? window['_'] : typeof global !== "undefined" ? global['_'] : null);
    var util = require('./util');


    /**
     * @module Excel/SharedStrings
     */
    var sharedStrings = function () {
      this.strings = {};
      this.stringArray = [];
      this.id = _.uniqueId('SharedStrings');
    };
    _.extend(sharedStrings.prototype, {
      /**
       * Adds a string to the shared string file, and returns the ID of the
       * string which can be used to reference it in worksheets.
       *
       * @param string {String}
       * @return int
       */
      addString: function (string) {
        this.strings[string] = this.stringArray.length;
        this.stringArray[this.stringArray.length] = string;
        return this.strings[string];
      },

      exportData: function () {
        return this.strings;
      },

      toXML: function () {
        var doc = util.createXmlDoc(util.schemas.spreadsheetml, 'sst');
        var sharedStringTable = doc.documentElement;
        this.stringArray.reverse();
        var l = this.stringArray.length;
        sharedStringTable.setAttribute('count', l);
        sharedStringTable.setAttribute('uniqueCount', l);

        var template = doc.createElement('si');
        var templateValue = doc.createElement('t');
        templateValue.appendChild(doc.createTextNode('--placeholder--'));
        template.appendChild(templateValue);
        var strings = this.stringArray;

        while (l--) {
          var clone = template.cloneNode(true);
          clone.firstChild.firstChild.nodeValue = strings[l];
          sharedStringTable.appendChild(clone);
        }

        return doc;
      }
    });
    module.exports = sharedStrings;
  }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
},{"./util":28}],19:[function(require,module,exports){
  (function (global,Buffer){
    "use strict";

    /**
     * @module Excel/SheetProtection
     *
     * https://msdn.microsoft.com/en-us/library/documentformat.openxml.spreadsheet.pane%28v=office.14%29.aspx
     */
    var _ = (typeof window !== "undefined" ? window['_'] : typeof global !== "undefined" ? global['_'] : null);
    var util = require('./util');

    var SheetProtection = function () {
      this.algorithmName = null;
      this.autoFilter = null;
      this.deleteColumns = null;
      this.deleteRows = null;
      this.formatCells = null;
      this.formatColumns = null;
      this.formatRows = null;
      this.unhashedValue = null;
      this.hashValue = null;
      this.insertColumns = null;
      this.insertHyperlinks = null;
      this.insertRows = null;
      this.objects = null;
      this.pivotTables = null;
      this.saltValue = null;
      this.scenarios = null;
      this.selectLockedCells = null;
      this.selectUnlockedCells = null;
      this.sheet = true; //Otherwise this is a bit pointless, don't you think?
      this.sort = null;
      this.spinCount = null;
    };

    _.extend(SheetProtection.prototype, {

      exportXML: function (doc) {
        var attrs = {};
        var sheetProtection = doc.createElement('sheetProtection', attrs);

        if(this.sheet === true) {

          if(this.unhashedValue) {
            var forge = require('node-forge');
            var md = forge.md[this.algorithmName].create();
            if(!this.saltValue) {
              //Bad human! Bad!
              this.saltValue = Math.random().toString(36).substr(2, 5);
            }
            var spinCount = this.spinCount = this.spinCount || 1000;
            var pass = this.saltValue + '' + this.unhashedValue;

            this.saltValue = new Buffer(this.saltValue).toString('base64')

            while(spinCount--) {
              md.update(pass);
              pass=md.digest().toHex();
            }

            this.hashValue = new Buffer(pass).toString('base64');

          }

          util.setAttributesOnDoc(sheetProtection, {
            algorithmName: this.algorithmName,
            autoFilter: {v: this.autoFilter, type: Boolean},
            deleteColumns: {v: this.deleteColumns, type: Boolean},
            deleteRows: {v: this.deleteRows, type: Boolean},
            formatCells: {v: this.formatCells, type: Boolean},
            formatColumns: {v: this.formatColumns, type: Boolean},
            formatRows: {v: this.formatRows, type: Boolean},
            hashValue: this.hashValue,
            insertColumns: {v: this.insertColumns, type: Boolean},
            insertHyperlinks: {v: this.insertHyperlinks, type: Boolean},
            insertRows: {v: this.insertRows, type: Boolean},
            objects: {v: this.objects, type: Boolean},
            pivotTables: {v: this.pivotTables, type: Boolean},
            saltValue: this.saltValue,
            scenarios: {v: this.scenarios, type: Boolean},
            selectLockedCells: {v: this.selectLockedCells, type: Boolean},
            selectUnlockedCells: {v: this.selectUnlockedCells, type: Boolean},
            sheet: {v: this.sheet, type: Boolean},
            spinCount: this.spinCount
          });
        }

        return sheetProtection;
      }
    });

    SheetProtection.algorithms = {MD5: 'md5', SHA1: 'sha1', SHA256: 'sha256', SHA384: 'sha384', SHA512: 'sha512'};


    module.exports = SheetProtection;
  }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {},require("buffer").Buffer)
},{"./util":28,"buffer":1,"node-forge":6}],20:[function(require,module,exports){
  (function (global){
    /**
     * @module Excel/SheetView
     *
     * https://msdn.microsoft.com/en-us/library/documentformat.openxml.spreadsheet.sheetview%28v=office.14%29.aspx
     *
     */
    "use strict";
    var _ = (typeof window !== "undefined" ? window['_'] : typeof global !== "undefined" ? global['_'] : null);
    var Pane = require('./Pane');
    var util = require('./util')

    var SheetView = function (config) {
      config = config || {};

      this.pane = config.pane || new Pane();
      this.showZeros = null; //Default
      this.defaultGridColor = null;
      this.colorId = null;
      this.rightToLeft = null;
      this.showFormulas = null;
      this.showGridLines = null;
      this.showOutlineSymbols = null;
      this.showRowColHeaders = null;
      this.showRuler = null;
      this.showWhiteSpace = null;
      this.tabSelected = null;
      this.topLeftCell = null;
      this.viewType = null; //http://www.datypic.com/sc/ooxml/t-ssml_ST_SheetViewType.html
      this.windowProtection = null;
      this.zoomScale = null;
      this.zoomScaleNormal = null;
      this.zoomScalePageLayoutView = null;
      this.zoomScaleSheetLayoutView = null;
    };

    _.extend(SheetView.prototype, {

      /**
       * Added froze pane
       * @param column - column number: 0, 1, 2 ...
       * @param row - row number: 0, 1, 2 ...
       * @param cell - 'A1'
       * @deprecated
       */
      freezePane: function(column, row, cell) {
        this.pane.state = 'frozen';
        this.pane.xSplit = column;
        this.pane.ySplit = row;
        this.pane.topLeftCell = cell;
      },

      exportXML: function (doc) {
        var sheetViews = doc.createElement('sheetViews'),
          sheetView = doc.createElement('sheetView');

        util.setAttributesOnDoc(sheetView, {
          //TODO apparent you can add 'book views'.. investigate what these are
          workbookViewId: 0,
          showZeros: {v: this.showZeros, type: Boolean},
          defaultGridColor:  {v: this.defaultGridColor, type: Boolean},
          //TODO: I have no idea what this even is :\
          colorId: this.colorId,
          rightToLeft:  {v: this.rightToLeft, type: Boolean},
          showFormulas:  {v: this.showFormulas, type: Boolean},
          showGridLines:  {v: this.showGridLines, type: Boolean},
          showOutlineSymbols:  {v: this.showOutlineSymbols, type: Boolean},
          showRowColHeaders:  {v: this.showRowColHeaders, type: Boolean},
          showRuler:  {v: this.showRuler, type: Boolean},
          showWhiteSpace:  {v: this.showWhiteSpace, type: Boolean},
          tabSelected:  {v: this.tabSelected, type: Boolean},
          viewType: this.viewType,
          windowProtection:  {v: this.windowProtection, type: Boolean},
          zoomScale:  {v: this.zoomScale, type: Boolean},
          zoomScaleNormal: this.zoomScaleNormal,
          zoomScalePageLayoutView: this.zoomScalePageLayoutView,
          zoomScaleSheetLayoutView: this.zoomScaleSheetLayoutView
        });

        sheetView.appendChild(this.pane.exportXML(doc));

        sheetViews.appendChild(sheetView);
        return sheetViews;
      }
    });

    module.exports = SheetView;
  }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
},{"./Pane":14,"./util":28}],21:[function(require,module,exports){
  (function (global){
    /**
     * @module Excel/StyleSheet
     */
    "use strict";
    var _ = (typeof window !== "undefined" ? window['_'] : typeof global !== "undefined" ? global['_'] : null);
    var util = require('./util');

    var StyleSheet = function () {
      this.id = _.uniqueId('StyleSheet');
      this.cellStyles = [{
        name:"Normal",
        xfId:"0",
        builtinId:"0"
      }];
      this.defaultTableStyle = false;
      this.differentialStyles = [{}];
      this.masterCellFormats = [{
        numFmtId: 0,
        fontId: 0,
        fillId: 0,
        borderId: 0,
        xfid: 0
      }];
      this.masterCellStyles = [{
        numFmtId: 0,
        fontId: 0,
        fillId: 0,
        borderId: 0
      }];
      this.fonts = [{}];
      this.numberFormatters = [];
      this.fills = [{}, {
        type: 'pattern',
        patternType: 'gray125',
        fgColor: 'FF333333',
        bgColor: 'FF333333'
      }];
      this.borders = [{
        top: {},
        left: {},
        right: {},
        bottom: {},
        diagonal: {}
      }];
      this.tableStyles = [];
    };
    _.extend(StyleSheet.prototype, {
      createSimpleFormatter: function (type) {
        var sid = this.masterCellFormats.length;
        var style = {
          id: sid
        };
        switch(type) {
          case 'date':
            style.numFmtId = 14;
            break;
        }
        this.masterCellFormats.push(style);
        return style;
      },

      createFill: function (fillInstructions) {
        var id = this.fills.length;
        var fill = fillInstructions;
        fill.id = id;
        this.fills.push(fill);
        return fill;
      },

      createNumberFormatter: function (formatInstructions) {
        var id = this.numberFormatters.length + 100;
        var format = {
          id: id,
          formatCode: formatInstructions
        };
        this.numberFormatters.push(format);
        return format;
      },

      /**
       * alignment: {
    *  horizontal: http://www.schemacentral.com/sc/ooxml/t-ssml_ST_HorizontalAlignment.html
    *  vertical: http://www.schemacentral.com/sc/ooxml/t-ssml_ST_VerticalAlignment.html
       *  @param {Object} styleInstructions
       */
      createFormat: function (styleInstructions) {
        var sid = this.masterCellFormats.length;
        var style = {
          id: sid
        };
        if (styleInstructions.protection) {
          style.protection = styleInstructions.protection;
        }
        if(styleInstructions.font && _.isObject(styleInstructions.font)) {
          style.fontId = this.createFontStyle(styleInstructions.font).id;
        } else if(styleInstructions.font) {
          if(_.isNaN(parseInt(styleInstructions.font, 10))) {
            throw "Passing a non-numeric font id is not supported";
          }
          style.fontId = styleInstructions.font;
        }

        if (styleInstructions.format && _.isString(styleInstructions.format)) {
          style.numFmtId = this.createNumberFormatter(styleInstructions.format).id;
        } else if(styleInstructions.format) {
          if(_.isNaN(parseInt(styleInstructions.format, 10))) {
            throw "Invalid number formatter id";
          }
          style.numFmtId = styleInstructions.format;
        }

        if (styleInstructions.border && _.isObject(styleInstructions.border)) {
          style.borderId = this.createBorderFormatter(styleInstructions.border).id;
        } else if (styleInstructions.border) {
          if(_.isNaN(parseInt(styleInstructions.border, 10))) {
            throw "Passing a non-numeric border id is not supported";
          }
          style.borderId = styleInstructions.border;
        }

        if (styleInstructions.fill && _.isObject(styleInstructions.fill)) {
          style.fillId = this.createFill(styleInstructions.fill).id;
        } else if (styleInstructions.fill) {
          if(_.isNaN(parseInt(styleInstructions.fill, 10))) {
            throw "Passing a non-numeric fill id is not supported";
          }
          style.fillId = styleInstructions.fill;
        }

        if (styleInstructions.alignment && _.isObject(styleInstructions.alignment)) {
          style.alignment = _.pick(
            styleInstructions.alignment,
            'horizontal',
            'justifyLastLine',
            'readingOrder',
            'relativeIndent',
            'shrinkToFit',
            'textRotation',
            'vertical',
            'wrapText'
          );
        }

        this.masterCellFormats.push(style);
        return style;
      },

      createDifferentialStyle: function (styleInstructions) {
        var id = this.differentialStyles.length;
        var style = {
          id: id
        };
        if(styleInstructions.font && _.isObject(styleInstructions.font)) {
          style.font = styleInstructions.font;
        }
        if (styleInstructions.border && _.isObject(styleInstructions.border)) {
          style.border = _.defaults(styleInstructions.border, {
            top: {},
            left: {},
            right: {},
            bottom: {},
            diagonal: {}
          });
        }
        if (styleInstructions.fill && _.isObject(styleInstructions.fill)) {
          style.fill = styleInstructions.fill;
        }
        if (styleInstructions.alignment && _.isObject(styleInstructions.alignment)) {
          style.alignment = styleInstructions.alignment;
        }
        if (styleInstructions.format && _.isString(styleInstructions.format)) {
          style.numFmt = styleInstructions.format;
        }
        this.differentialStyles[id] = style;
        return style;
      },

      /**
       * Should be an object containing keys that match with one of the keys from this list:
       * http://www.schemacentral.com/sc/ooxml/t-ssml_ST_TableStyleType.html
       *
       * The value should be a reference to a differential format (dxf)
       * @param {Object} instructions
       */
      createTableStyle: function (instructions) {
        this.tableStyles.push(instructions);
      },

      /**
       * All params optional
       * Expects: {
    * top: {},
    * left: {},
    * right: {},
    * bottom: {},
    * diagonal: {},
    * outline: boolean,
    * diagonalUp: boolean,
    * diagonalDown: boolean
    * }
       * Each border should follow:
       * {
    * style: styleString, http://www.schemacentral.com/sc/ooxml/t-ssml_ST_BorderStyle.html
    * color: ARBG color (requires the A, so for example FF006666)
    * }
       * @param {Object} border
       */
      createBorderFormatter: function (border) {
        _.defaults(border, {
          top: {},
          left: {},
          right: {},
          bottom: {},
          diagonal: {},
          id: this.borders.length
        });
        this.borders.push(border);
        return border;
      },

      /**
       * Supported font styles:
       * bold
       * italic
       * underline (single, double, singleAccounting, doubleAccounting)
       * size
       * color
       * fontName
       * strike (strikethrough)
       * outline (does this actually do anything?)
       * shadow (does this actually do anything?)
       * superscript
       * subscript
       *
       * Color is a future goal - at the moment it's looking a bit complicated
       * @param {Object} instructions
       */
      createFontStyle: function (instructions) {
        var fontId = this.fonts.length;
        var fontStyle = {
          id: fontId
        };
        if(instructions.bold) {
          fontStyle.bold = true;
        }
        if(instructions.italic) {
          fontStyle.italic = true;
        }
        if(instructions.superscript) {
          fontStyle.vertAlign = 'superscript';
        }
        if(instructions.subscript) {
          fontStyle.vertAlign = 'subscript';
        }
        if(instructions.underline) {
          if(_.indexOf([
              'double',
              'singleAccounting',
              'doubleAccounting'
            ], instructions.underline) !== -1) {
            fontStyle.underline = instructions.underline;
          } else {
            fontStyle.underline = true;
          }
        }
        if(instructions.strike) {
          fontStyle.strike = true;
        }
        if(instructions.outline) {
          fontStyle.outline = true;
        }
        if(instructions.shadow) {
          fontStyle.shadow = true;
        }
        if(instructions.size) {
          fontStyle.size = instructions.size;
        }
        if(instructions.color) {
          fontStyle.color = instructions.color;
        }
        if(instructions.fontName) {
          fontStyle.fontName = instructions.fontName;
        }
        this.fonts.push(fontStyle);
        return fontStyle;
      },

      exportBorders: function (doc) {
        var borders = doc.createElement('borders');
        borders.setAttribute('count', this.borders.length);

        for(var i = 0, l = this.borders.length; i < l; i++) {
          borders.appendChild(this.exportBorder(doc, this.borders[i]));
        }
        return borders;
      },

      exportBorder: function (doc, data) {
        var border = doc.createElement('border');
        var self = this;
        var borderGenerator = function (name) {
          var b = doc.createElement(name);
          if(data[name].style) {
            b.setAttribute('style', data[name].style);
          }
          if(data[name].color) {
            b.appendChild(self.exportColor(doc, data[name].color));
          }
          return b;
        };
        border.appendChild(borderGenerator('left'));
        border.appendChild(borderGenerator('right'));
        border.appendChild(borderGenerator('top'));
        border.appendChild(borderGenerator('bottom'));
        border.appendChild(borderGenerator('diagonal'));
        return border;
      },

      exportColor: function (doc, color) {
        var colorEl = doc.createElement('color');
        if(_.isString(color)) {
          colorEl.setAttribute('rgb', color);
          return colorEl;
        }

        if (!_.isUndefined(color.tint)) {
          colorEl.setAttribute('tint', color.tint);
        }
        if (!_.isUndefined(color.auto)) {
          colorEl.setAttribute('auto', !!color.auto);
        }
        if (!_.isUndefined(color.theme)) {
          colorEl.setAttribute('theme', color.theme);
        }

        return colorEl;
      },

      exportMasterCellFormats: function (doc) {
        var cellFormats = util.createElement(doc, 'cellXfs', [
          ['count', this.masterCellFormats.length]
        ]);
        for(var i = 0, l = this.masterCellFormats.length; i < l; i++) {
          var mformat = this.masterCellFormats[i];
          cellFormats.appendChild(this.exportCellFormatElement(doc, mformat));
        }
        return cellFormats;
      },

      exportMasterCellStyles: function (doc) {
        var records = util.createElement(doc, 'cellStyleXfs', [
          ['count', this.masterCellStyles.length]
        ]);
        for(var i = 0, l = this.masterCellStyles.length; i < l; i++) {
          var mstyle = this.masterCellStyles[i];
          records.appendChild(this.exportCellFormatElement(doc, mstyle));
        }
        return records;
      },

      exportCellFormatElement: function (doc, styleInstructions) {
        var xf = doc.createElement('xf');
        var allowed = ['applyAlignment', 'applyBorder', 'applyFill', 'applyFont', 'applyNumberFormat',
          'applyProtection', 'borderId', 'fillId', 'fontId', 'numFmtId', 'pivotButton', 'quotePrefix', 'xfId'];
        var attributes = _.filter(_.keys(styleInstructions), function (key) {
          if(_.indexOf(allowed, key) !== -1) {
            return true;
          }
        });
        if(styleInstructions.alignment) {
          var alignmentData = styleInstructions.alignment;
          xf.appendChild(this.exportAlignment(doc, alignmentData));
        }
        if (styleInstructions.protection) {
          xf.appendChild(this.exportProtection(doc, styleInstructions.protection));
          xf.setAttribute('applyProtection', '1');
        }
        var a = attributes.length;
        while(a--) {
          xf.setAttribute(attributes[a], styleInstructions[attributes[a]]);
        }
        if (styleInstructions.fillId) {
          xf.setAttribute('applyFill', '1');
        }
        if (styleInstructions.fontId) {
          xf.setAttribute('applyFont', '1');
        }
        if (styleInstructions.borderId) {
          xf.setAttribute('applyBorder', '1');
        }
        if (styleInstructions.alignment) {
          xf.setAttribute('applyAlignment', '1');
        }
        if (styleInstructions.numFmtId) {
          xf.setAttribute('applyNumberFormat', '1');
        }
        if((styleInstructions.numFmtId !== undefined) && (styleInstructions.xfId === undefined)) {
          xf.setAttribute('xfId', '0');
        }
        return xf;
      },

      exportAlignment: function (doc, alignmentData) {
        var alignment = doc.createElement('alignment');
        var keys = _.keys(alignmentData);
        for(var i = 0, l = keys.length; i < l; i++) {
          alignment.setAttribute(keys[i], alignmentData[keys[i]]);
        }
        return alignment;
      },

      exportFonts: function (doc) {
        var fonts = doc.createElement('fonts');
        fonts.setAttribute('count', this.fonts.length);
        for(var i = 0, l = this.fonts.length; i < l; i++) {
          var fd = this.fonts[i];
          fonts.appendChild(this.exportFont(doc, fd));
        }
        return fonts;
      },

      exportFont: function (doc, fd) {
        var font = doc.createElement('font');
        if(fd.size) {
          var size = doc.createElement('sz');
          size.setAttribute('val', fd.size);
          font.appendChild(size);
        }

        if(fd.fontName) {
          var fontName = doc.createElement('name');
          fontName.setAttribute('val', fd.fontName);
          font.appendChild(fontName);
        }

        if(fd.bold) {
          font.appendChild(doc.createElement('b'));
        }
        if(fd.italic) {
          font.appendChild(doc.createElement('i'));
        }
        if(fd.vertAlign) {
          var vertAlign = doc.createElement('vertAlign');
          vertAlign.setAttribute('val', fd.vertAlign);
          font.appendChild(vertAlign);
        }
        if(fd.underline) {
          var u = doc.createElement('u');
          if(fd.underline !== true) {
            u.setAttribute('val', fd.underline);
          }
          font.appendChild(u);
        }
        if(fd.strike) {
          font.appendChild(doc.createElement('strike'));
        }
        if(fd.shadow) {
          font.appendChild(doc.createElement('shadow'));
        }
        if(fd.outline) {
          font.appendChild(doc.createElement('outline'));
        }
        if(fd.color) {
          font.appendChild(this.exportColor(doc, fd.color));
        }
        return font;
      },

      exportFills: function (doc) {
        var fills = doc.createElement('fills');
        fills.setAttribute('count', this.fills.length);
        for(var i = 0, l = this.fills.length; i < l; i++) {
          var fd = this.fills[i];
          fills.appendChild(this.exportFill(doc, fd));
        }
        return fills;
      },

      exportFill: function (doc, fd) {
        var fillDef;
        var fill = doc.createElement('fill');
        if (fd.type === 'pattern') {
          fillDef = this.exportPatternFill(doc, fd);
          fill.appendChild(fillDef);
        } else if (fd.type === 'gradient') {
          fillDef = this.exportGradientFill(doc, fd);
          fill.appendChild(fillDef);
        }
        return fill;
      },

      exportGradientFill: function (doc, data) {
        var fillDef = doc.createElement('gradientFill');
        if(data.degree) {
          fillDef.setAttribute('degree', data.degree);
        } else if (data.left) {
          fillDef.setAttribute('left', data.left);
          fillDef.setAttribute('right', data.right);
          fillDef.setAttribute('top', data.top);
          fillDef.setAttribute('bottom', data.bottom);
        }
        var start = doc.createElement('stop');
        start.setAttribute('position', data.start.pureAt || 0);
        var startColor = doc.createElement('color');
        if (typeof data.start === 'string' || data.start.color) {
          startColor.setAttribute('rgb', data.start.color || data.start);
        } else if (typeof data.start.theme) {
          startColor.setAttribute('theme', data.start.theme);
        }

        var end = doc.createElement('stop');
        var endColor = doc.createElement('color');
        end.setAttribute('position', data.end.pureAt || 1);
        if (typeof data.start === 'string' || data.end.color) {
          endColor.setAttribute('rgb', data.end.color || data.end);
        } else if (typeof data.end.theme) {
          endColor.setAttribute('theme', data.end.theme);
        }
        start.appendChild(startColor);
        end.appendChild(endColor);
        fillDef.appendChild(start);
        fillDef.appendChild(end);
        return fillDef;
      },

      /**
       * Pattern types: http://www.schemacentral.com/sc/ooxml/t-ssml_ST_PatternType.html
       * @param {XMLDoc} doc
       * @param {Object} data
       */
      exportPatternFill: function (doc, data) {
        var fillDef = util.createElement(doc, 'patternFill', [
          ['patternType', data.patternType]
        ]);
        if(!data.bgColor) {
          data.bgColor = 'FFFFFFFF';
        }
        if(!data.fgColor) {
          data.fgColor = 'FFFFFFFF';
        }

        var bgColor = doc.createElement('bgColor');
        if(_.isString(data.bgColor)) {
          bgColor.setAttribute('rgb', data.bgColor);
        } else {
          if(data.bgColor.theme) {
            bgColor.setAttribute('theme', data.bgColor.theme);
          } else {
            bgColor.setAttribute('rgb', data.bgColor.rbg);
          }
        }

        var fgColor = doc.createElement('fgColor');
        if(_.isString(data.fgColor)) {
          fgColor.setAttribute('rgb', data.fgColor);
        } else {
          if(data.fgColor.theme) {
            fgColor.setAttribute('theme', data.fgColor.theme);
          } else {
            fgColor.setAttribute('rgb', data.fgColor.rbg);
          }
        }
        fillDef.appendChild(fgColor);
        fillDef.appendChild(bgColor);
        return fillDef;
      },

      exportNumberFormatters: function (doc) {
        var formatters = doc.createElement('numFmts');
        formatters.setAttribute('count', this.numberFormatters.length);
        for(var i = 0, l = this.numberFormatters.length; i < l; i++) {
          var fd = this.numberFormatters[i];
          formatters.appendChild(this.exportNumberFormatter(doc, fd));
        }
        return formatters;
      },

      exportNumberFormatter: function (doc, fd) {
        var numFmt = doc.createElement('numFmt');
        numFmt.setAttribute('numFmtId', fd.id);
        numFmt.setAttribute('formatCode', fd.formatCode);
        return numFmt;
      },

      exportCellStyles: function (doc) {
        var cellStyles = doc.createElement('cellStyles');
        cellStyles.setAttribute('count', this.cellStyles.length);

        for(var i = 0, l = this.cellStyles.length; i < l; i++) {
          var style = this.cellStyles[i];
          delete style.id; //Remove internal id
          var record = util.createElement(doc, 'cellStyle');
          cellStyles.appendChild(record);
          var attributes = _.keys(style);
          var a = attributes.length;
          while(a--) {
            record.setAttribute(attributes[a], style[attributes[a]]);
          }
        }

        return cellStyles;
      },

      exportDifferentialStyles: function (doc) {
        var dxfs = doc.createElement('dxfs');
        dxfs.setAttribute('count', this.differentialStyles.length);

        for(var i = 0, l = this.differentialStyles.length; i < l; i++) {
          var style = this.differentialStyles[i];
          dxfs.appendChild(this.exportDFX(doc, style));
        }

        return dxfs;
      },

      exportDFX: function (doc, style) {
        var dxf = doc.createElement('dxf');
        if(style.font) {
          dxf.appendChild(this.exportFont(doc, style.font));
        }
        if(style.fill) {
          dxf.appendChild(this.exportFill(doc, style.fill));
        }
        if(style.border) {
          dxf.appendChild(this.exportBorder(doc, style.border));
        }
        if(style.numFmt) {
          dxf.appendChild(this.exportNumberFormatter(doc, style.numFmt));
        }
        if(style.alignment) {
          dxf.appendChild(this.exportAlignment(doc, style.alignment));
        }
        return dxf;
      },

      exportTableStyles: function (doc) {
        var tableStyles = doc.createElement('tableStyles');
        tableStyles.setAttribute('count', this.tableStyles.length);
        if(this.defaultTableStyle) {
          tableStyles.setAttribute('defaultTableStyle', this.defaultTableStyle);
        }
        for(var i = 0, l = this.tableStyles.length; i < l; i++) {
          tableStyles.appendChild(this.exportTableStyle(doc, this.tableStyles[i]));
        }
        return tableStyles;
      },

      exportTableStyle: function (doc, style) {
        var tableStyle = doc.createElement('tableStyle');
        tableStyle.setAttribute('name', style.name);
        tableStyle.setAttribute('pivot', 0);
        var i = 0;

        _.each(style, function (value, key) {
          if(key === 'name') {return;}
          i++;
          var styleEl = doc.createElement('tableStyleElement');
          styleEl.setAttribute('type', key);
          styleEl.setAttribute('dxfId', value);
          tableStyle.appendChild(styleEl);
        });
        tableStyle.setAttribute('count', i);
        return tableStyle;
      },

      exportProtection: function (doc, protectionData) {
        var node = doc.createElement('protection');
        for (var k in protectionData) {
          if(protectionData.hasOwnProperty(k)) {
            node.setAttribute(k, protectionData[k]);
          }
        }
        return node;
      },

      toXML: function () {
        var doc = util.createXmlDoc(util.schemas.spreadsheetml, 'styleSheet');
        var styleSheet = doc.documentElement;
        styleSheet.appendChild(this.exportNumberFormatters(doc));
        styleSheet.appendChild(this.exportFonts(doc));
        styleSheet.appendChild(this.exportFills(doc));
        styleSheet.appendChild(this.exportBorders(doc));
        styleSheet.appendChild(this.exportMasterCellStyles(doc));
        styleSheet.appendChild(this.exportMasterCellFormats(doc));
        styleSheet.appendChild(this.exportCellStyles(doc));
        styleSheet.appendChild(this.exportDifferentialStyles(doc));
        if(this.tableStyles.length) {
          styleSheet.appendChild(this.exportTableStyles(doc));
        }
        return doc;
      }
    });
    module.exports = StyleSheet;

  }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
},{"./util":28}],22:[function(require,module,exports){
  (function (global){
    "use strict";
    var _ = (typeof window !== "undefined" ? window['_'] : typeof global !== "undefined" ? global['_'] : null);
    var util = require('./util');

    /**
     * @module Excel/Table
     */

    var Table = function (config) {
      _.defaults(this, {
        name: "",
        displayName: "",
        dataCellStyle: null,
        dataDfxId: null,
        headerRowBorderDxfId: null,
        headerRowCellStyle: null,
        headerRowCount: 1,
        headerRowDxfId: null,
        insertRow: false,
        insertRowShift: false,
        ref: null,
        tableBorderDxfId: null,
        totalsRowBorderDxfId: null,
        totalsRowCellStyle: null,
        totalsRowCount: 0,
        totalsRowDxfId: null,
        tableColumns: [],
        autoFilter: null,
        sortState: null,
        styleInfo: {}
      });
      this.initialize(config);
    };
    _.extend(Table.prototype, {

      initialize: function (config) {
        this.displayName = _.uniqueId("Table");
        this.name = this.displayName;
        this.id = this.name;
        this.tableId = this.id.replace('Table', '');
        _.extend(this, config);
      },

      setReferenceRange: function (start, end) {
        this.ref = [start, end];
      },

      setTableColumns: function (columns) {
        _.each(columns, function (column) {
          this.addTableColumn(column);
        }, this);
      },

      /**
       * Expects an object with the following optional properties:
       * name (required)
       * dataCellStyle
       * dataDxfId
       * headerRowCellStyle
       * headerRowDxfId
       * totalsRowCellStyle
       * totalsRowDxfId
       * totalsRowFunction
       * totalsRowLabel
       * columnFormula
       * columnFormulaIsArrayType (boolean)
       * totalFormula
       * totalFormulaIsArrayType (boolean)
       */
      addTableColumn: function (column) {
        if(_.isString(column)) {
          column = {
            name: column
          };
        }
        if(!column.name) {
          throw "Invalid argument for addTableColumn - minimum requirement is a name property";
        }
        this.tableColumns.push(column);
      },

      /**
       * Expects an object with the following properties:
       * caseSensitive (boolean)
       * dataRange
       * columnSort (assumes true)
       * sortDirection
       * sortRange (defaults to dataRange)
       */
      setSortState: function (state) {
        this.sortState = state;
      },

      toXML: function () {
        var doc = util.createXmlDoc(util.schemas.spreadsheetml, 'table');
        var table = doc.documentElement;
        table.setAttribute('id', this.tableId);
        table.setAttribute('name', this.name);
        table.setAttribute('displayName', this.displayName);
        var s = this.ref[0];
        var e = this.ref[1];
        table.setAttribute('ref', util.positionToLetterRef(s[0], s[1]) + ":" + util.positionToLetterRef(e[0], e[1]));

        /** TOTALS **/
        table.setAttribute('totalsRowCount', this.totalsRowCount);

        /** HEADER **/
        table.setAttribute('headerRowCount', this.headerRowCount);
        if(this.headerRowDxfId) {
          table.setAttribute('headerRowDxfId', this.headerRowDxfId);
        }
        if(this.headerRowBorderDxfId) {
          table.setAttribute('headerRowBorderDxfId', this.headerRowBorderDxfId);
        }

        if(!this.ref) {
          throw "Needs at least a reference range";
        }
        if(!this.autoFilter) {
          this.addAutoFilter(this.ref[0], this.ref[1]);
        }

        table.appendChild(this.exportAutoFilter(doc));

        table.appendChild(this.exportTableColumns(doc));
        table.appendChild(this.exportTableStyleInfo(doc));
        return doc;
      },

      exportTableColumns: function (doc) {
        var tableColumns = doc.createElement('tableColumns');
        tableColumns.setAttribute('count', this.tableColumns.length);
        var tcs = this.tableColumns;
        for(var i = 0, l = tcs.length; i < l; i++) {
          var tc = tcs[i];
          var tableColumn = doc.createElement('tableColumn');
          tableColumn.setAttribute('id', i + 1);
          tableColumn.setAttribute('name', tc.name);
          tableColumns.appendChild(tableColumn);

          if(tc.totalsRowFunction) {
            tableColumn.setAttribute('totalsRowFunction', tc.totalsRowFunction);
          }
          if(tc.totalsRowLabel) {
            tableColumn.setAttribute('totalsRowLabel', tc.totalsRowLabel);
          }
        }
        return tableColumns;
      },

      exportAutoFilter: function (doc) {
        var autoFilter = doc.createElement('autoFilter');
        var s = this.autoFilter[0];
        var e = this.autoFilter[1];
        autoFilter.setAttribute('ref', util.positionToLetterRef(s[0], s[1]) + ":" + util.positionToLetterRef(e[0], e[1]  - this.totalsRowCount));
        return autoFilter;
      },

      exportTableStyleInfo: function (doc) {
        var ts = this.styleInfo;
        var tableStyle = doc.createElement('tableStyleInfo');
        tableStyle.setAttribute('name', ts.themeStyle);
        tableStyle.setAttribute('showFirstColumn', ts.showFirstColumn ? "1" : "0");
        tableStyle.setAttribute('showLastColumn', ts.showLastColumn ? "1" : "0");
        tableStyle.setAttribute('showColumnStripes', ts.showColumnStripes ? "1" : "0");
        tableStyle.setAttribute('showRowStripes', ts.showRowStripes ? "1" : "0");
        return tableStyle;
      },

      addAutoFilter: function (startRef, endRef) {
        this.autoFilter = [startRef, endRef];
      }
    });
    module.exports = Table;
  }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
},{"./util":28}],23:[function(require,module,exports){
  (function (global){
    "use strict";
    var Q = require('q');
    var _ = (typeof window !== "undefined" ? window['_'] : typeof global !== "undefined" ? global['_'] : null);
    var util = require('./util');
    var StyleSheet = require('./StyleSheet');
    var Worksheet = require('./Worksheet');
    var SharedStrings = require('./SharedStrings');
    var RelationshipManager = require('./RelationshipManager');
    var Paths = require('./Paths');
    var XMLDOM = require('./XMLDOM');

    /**
     * @module Excel/Workbook
     */
    /* globals console: true */

    var Workbook = function (config) {
      this.worksheets = [];
      this.tables = [];
      this.drawings = [];
      this.media = {};
      this.initialize(config);
    };
    _.extend(Workbook.prototype, {

      initialize: function () {
        this.id = _.uniqueId('Workbook');
        this.styleSheet = new StyleSheet();
        this.sharedStrings = new SharedStrings();
        this.relations = new RelationshipManager();
        this.relations.addRelation(this.styleSheet, 'stylesheet');
        this.relations.addRelation(this.sharedStrings, 'sharedStrings');
      },

      createWorksheet: function (config) {
        config = config || {};
        _.defaults(config, {
          name: 'Sheet '.concat(this.worksheets.length + 1)
        });
        return new Worksheet(config);
      },

      getStyleSheet: function () {
        return this.styleSheet;
      },

      addTable: function (table) {
        this.tables.push(table);
      },

      addDrawings: function (drawings) {
        this.drawings.push(drawings);
      },

      addMedia: function (type, fileName, fileData, contentType) {
        var fileNamePieces = fileName.split('.');
        var extension = fileNamePieces[fileNamePieces.length - 1];
        if(!contentType) {
          switch(extension.toLowerCase()) {
            case 'jpeg':
            case 'jpg':
              contentType = "image/jpeg";
              break;
            case 'png':
              contentType = "image/png";
              break;
            case 'gif':
              contentType = "image/gif";
              break;
            default:
              contentType = null;
              break;
          }
        }
        if(!this.media[fileName]) {
          this.media[fileName] = {
            id: fileName,
            data: fileData,
            fileName: fileName,
            contentType: contentType,
            extension: extension
          };
        }
        return this.media[fileName];
      },

      addWorksheet: function (worksheet) {
        this.relations.addRelation(worksheet, 'worksheet');
        worksheet.setSharedStringCollection(this.sharedStrings);
        this.worksheets.push(worksheet);
      },

      createContentTypes: function () {
        var doc = util.createXmlDoc(util.schemas.contentTypes, 'Types');
        var types = doc.documentElement;
        var i, l;

        types.appendChild(util.createElement(doc, 'Default', [
          ['Extension', "rels"],
          ['ContentType', "application/vnd.openxmlformats-package.relationships+xml"]
        ]));
        types.appendChild(util.createElement(doc, 'Default', [
          ['Extension', "xml"],
          ['ContentType', "application/xml"]
        ]));

        var extensions = {};
        for(var filename in this.media) {
          if(this.media.hasOwnProperty(filename)) {
            extensions[this.media[filename].extension] = this.media[filename].contentType;
          }
        }
        for(var extension in extensions) {
          if(extensions.hasOwnProperty(extension)) {
            types.appendChild(util.createElement(doc, 'Default', [
              ['Extension', extension],
              ['ContentType', extensions[extension]]
            ]));
          }
        }

        types.appendChild(util.createElement(doc, 'Override', [
          ['PartName', "/xl/workbook.xml"],
          ['ContentType', "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml"]
        ]));
        types.appendChild(util.createElement(doc, 'Override', [
          ['PartName', "/xl/sharedStrings.xml"],
          ['ContentType', "application/vnd.openxmlformats-officedocument.spreadsheetml.sharedStrings+xml"]
        ]));
        types.appendChild(util.createElement(doc, 'Override', [
          ['PartName', "/xl/styles.xml"],
          ['ContentType', "application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml"]
        ]));

        for(i = 0, l = this.worksheets.length; i < l; i++) {
          types.appendChild(util.createElement(doc, 'Override', [
            ['PartName', "/xl/worksheets/sheet" + (i + 1) + ".xml"],
            ['ContentType', "application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml"]
          ]));
        }
        for(i = 0, l = this.tables.length; i < l; i++) {
          types.appendChild(util.createElement(doc, 'Override', [
            ['PartName', "/xl/tables/table" + (i + 1) + ".xml"],
            ['ContentType', "application/vnd.openxmlformats-officedocument.spreadsheetml.table+xml"]
          ]));
        }

        for(i = 0, l = this.drawings.length; i < l; i++) {
          types.appendChild(util.createElement(doc, 'Override', [
            ['PartName', '/xl/drawings/drawing' + (i + 1) + '.xml'],
            ['ContentType', 'application/vnd.openxmlformats-officedocument.drawing+xml']
          ]));
        }

        return doc;
      },

      toXML: function () {
        var doc = util.createXmlDoc(util.schemas.spreadsheetml, 'workbook');
        var wb = doc.documentElement;
        wb.setAttribute('xmlns:r', util.schemas.relationships);

        var maxWorksheetNameLength = 31;
        var sheets = util.createElement(doc, 'sheets');
        for(var i = 0, l = this.worksheets.length; i < l; i++) {
          var sheet = doc.createElement('sheet');
          // Microsoft Excel (2007, 2013) do not allow worksheet names longer than 31 characters
          // if the worksheet name is longer, Excel displays an "Excel found unreadable content..." popup when opening the file
          if(typeof console !== "undefined" && this.worksheets[i].name.length > maxWorksheetNameLength) {
            console.log('Microsoft Excel requires work sheet names to be less than ' + (maxWorksheetNameLength+1) +
              ' characters long, work sheet name "' + this.worksheets[i].name +
              '" is ' + this.worksheets[i].name.length + ' characters long');
          }
          sheet.setAttribute('name', this.worksheets[i].name);
          sheet.setAttribute('sheetId', i + 1);
          sheet.setAttribute('r:id', this.relations.getRelationshipId(this.worksheets[i]));
          sheets.appendChild(sheet);
        }
        wb.appendChild(sheets);
        return doc;
      },

      createWorkbookRelationship: function () {
        var doc = util.createXmlDoc(util.schemas.relationshipPackage, 'Relationships');
        var relationships = doc.documentElement;
        relationships.appendChild(util.createElement(doc, 'Relationship', [
          ['Id', 'rId1'],
          ['Type', util.schemas.officeDocument],
          ['Target', 'xl/workbook.xml']
        ]));
        return doc;
      },

      _generateCorePaths: function (files) {
        var i, l;
        Paths[this.styleSheet.id] = 'styles.xml';
        Paths[this.sharedStrings.id] = 'sharedStrings.xml';
        Paths[this.id] = '/xl/workbook.xml';

        for(i = 0, l = this.tables.length; i < l; i++) {
          files['/xl/tables/table' + (i + 1) + '.xml'] = this.tables[i].toXML();
          Paths[this.tables[i].id] = '/xl/tables/table' + (i + 1) + '.xml';
        }

        for(var fileName in this.media) {
          if(this.media.hasOwnProperty(fileName)) {
            var media = this.media[fileName];
            files['/xl/media/' + fileName] = media.data;
            Paths[fileName] = '/xl/media/' + fileName;
          }
        }

        for(i = 0, l = this.drawings.length; i < l; i++) {
          files['/xl/drawings/drawing' + (i + 1) + '.xml'] = this.drawings[i].toXML();
          Paths[this.drawings[i].id] = '/xl/drawings/drawing' + (i + 1) + '.xml';
          files['/xl/drawings/_rels/drawing' + (i + 1) + '.xml.rels'] = this.drawings[i].relations.toXML();
        }


      },

      _prepareFilesForPackaging: function (files) {

        _.extend(files, {
          '/[Content_Types].xml': this.createContentTypes(),
          '/_rels/.rels': this.createWorkbookRelationship(),
          '/xl/styles.xml': this.styleSheet.toXML(),
          '/xl/workbook.xml': this.toXML(),
          '/xl/sharedStrings.xml': this.sharedStrings.toXML(),
          '/xl/_rels/workbook.xml.rels': this.relations.toXML()
        });

        _.each(files, function (value, key) {
          if(key.indexOf('.xml') !== -1 || key.indexOf('.rels') !== -1) {
            if (value instanceof XMLDOM){
              files[key] = value.toString();
            } else {
              files[key] = value.xml || new window.XMLSerializer().serializeToString(value);
            }
            var content = files[key].replace(/xmlns=""/g, '');
            content = content.replace(/NS[\d]+:/g, '');
            content = content.replace(/xmlns:NS[\d]+=""/g, '');
            files[key] = '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>' + "\n" + content;
          }
        });
      },

      generateFiles: function () {
        var files = {};
        this._generateCorePaths(files);

        for(var i = 0, l = this.worksheets.length; i < l; i++) {
          files['/xl/worksheets/sheet' + (i + 1) + '.xml'] = this.worksheets[i].toXML();
          Paths[this.worksheets[i].id] = 'worksheets/sheet' + (i + 1) + '.xml';
          files['/xl/worksheets/_rels/sheet' + (i + 1) + '.xml.rels'] = this.worksheets[i].relations.toXML();
        }

        this._prepareFilesForPackaging(files);

        return Q.resolve(files);
      }
    });
    module.exports = Workbook;
  }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
},{"./Paths":15,"./RelationshipManager":17,"./SharedStrings":18,"./StyleSheet":21,"./Worksheet":24,"./XMLDOM":26,"./util":28,"q":"q"}],24:[function(require,module,exports){
  (function (global){
    "use strict";
    var _ = (typeof window !== "undefined" ? window['_'] : typeof global !== "undefined" ? global['_'] : null);
    var util = require('./util');
    var RelationshipManager = require('./RelationshipManager');
    var SheetView = require('./SheetView');

    /**
     * This module represents an excel worksheet in its basic form - no tables, charts, etc. Its purpose is
     * to hold data, the data's link to how it should be styled, and any links to other outside resources.
     *
     * @module Excel/Worksheet
     */
    var Worksheet = function (config) {
      this.relations = null;
      this.columnFormats = [];
      this.data = [];
      this.mergedCells = [];
      this.columns = [];
      this.sheetProtection = false;
      this._headers = [];
      this._footers = [];
      this._tables = [];
      this._drawings = [];
      this._rowInstructions = {};
      this._freezePane = {};

      this.hyperlinks = [];
      this.sheetView = config.sheetView || new SheetView();

      this.showZeros = null;
      this.initialize(config);
    };
    _.extend(Worksheet.prototype, {

      initialize: function (config) {
        config = config || {};
        this.name = config.name;
        this.id = _.uniqueId('Worksheet');
        this._timezoneOffset = new Date().getTimezoneOffset() * 60 * 1000;
        if(config.columns) {
          this.setColumns(config.columns);
        }

        this.relations = new RelationshipManager();
      },

      /**
       * Returns an object that can be consumed by a WorksheetExportWorker
       * @returns {Object}
       */
      exportData: function () {
        return {
          relations: this.relations.exportData(),
          columnFormats: this.columnFormats,
          data: this.data,
          columns: this.columns,
          mergedCells: this.mergedCells,
          _headers: this._headers,
          _footers: this._footers,
          _tables: this._tables,
          _rowInstructions: this._rowInstructions,
          _freezePane: this._freezePane,
          name: this.name,
          id: this.id
        };
      },

      /**
       * Imports data - to be used while inside of a WorksheetExportWorker.
       * @param {Object} data
       */
      importData: function (data) {
        this.relations.importData(data.relations);
        delete data.relations;
        _.extend(this, data);
      },

      setSharedStringCollection: function (stringCollection) {
        this.sharedStrings = stringCollection;
      },

      addTable: function (table) {
        this._tables.push(table);
        this.relations.addRelation(table, 'table');
      },

      addDrawings: function (table) {
        this._drawings.push(table);
        this.relations.addRelation(table, 'drawingRelationship');
      },

      setRowInstructions: function (rowIndex, instructions) {
        this._rowInstructions[rowIndex] = instructions;
      },

      /**
       * Expects an array length of three.
       *
       * @see Excel/Worksheet compilePageDetailPiece
       * @see <a href='/cookbook/addingHeadersAndFooters.html'>Adding headers and footers to a worksheet</a>
       *
       * @param {Array} headers [left, center, right]
       */
      setHeader: function (headers) {
        if(!_.isArray(headers)) {
          throw "Invalid argument type - setHeader expects an array of three instructions";
        }
        this._headers = headers;
      },

      /**
       * Expects an array length of three.
       *
       * @see Excel/Worksheet compilePageDetailPiece
       * @see <a href='/cookbook/addingHeadersAndFooters.html'>Adding headers and footers to a worksheet</a>
       *
       * @param {Array} footers [left, center, right]
       */
      setFooter: function (footers) {
        if(!_.isArray(footers)) {
          throw "Invalid argument type - setFooter expects an array of three instructions";
        }
        this._footers = footers;
      },

      /**
       * Turns page header/footer details into the proper format for Excel.
       * @param {type} data
       * @returns {String}
       */
      compilePageDetailPackage: function (data) {
        data = data || "";
        return [
          "&L", this.compilePageDetailPiece(data[0] || ""),
          "&C", this.compilePageDetailPiece(data[1] || ""),
          "&R", this.compilePageDetailPiece(data[2] || "")
        ].join('');
      },

      /**
       * Turns instructions on page header/footer details into something
       * usable by Excel.
       *
       * @param {type} data
       * @returns {String|@exp;_@call;reduce}
       */
      compilePageDetailPiece: function (data) {
        if(_.isString(data)) {
          return '&"-,Regular"'.concat(data);
        }
        if(_.isObject(data) && !_.isArray(data)) {
          var string = "";
          if(data.font || data.bold) {
            var weighting = data.bold ? "Bold" : "Regular";
            string += '&"' + (data.font || '-');
            string += ',' + weighting + '"';
          } else {
            string += '&"-,Regular"';
          }
          if(data.underline) {
            string += "&U";
          }
          if(data.fontSize) {
            string += "&"+data.fontSize;
          }
          string += data.text;

          return string;
        }

        if(_.isArray(data)) {
          var self = this;
          return _.reduce(data, function (m, v) {
            return m.concat(self.compilePageDetailPiece(v));
          }, "");
        }
      },

      /**
       * Creates the header node.
       *
       * @todo implement the ability to do even/odd headers
       * @param {XML Doc} doc
       * @returns {XML Node}
       */
      exportHeader: function (doc) {
        var oddHeader = doc.createElement('oddHeader');
        oddHeader.appendChild(doc.createTextNode(this.compilePageDetailPackage(this._headers)));
        return oddHeader;
      },

      /**
       * Creates the footer node.
       *
       * @todo implement the ability to do even/odd footers
       * @param {XML Doc} doc
       * @returns {XML Node}
       */
      exportFooter: function (doc) {
        var oddFooter = doc.createElement('oddFooter');
        oddFooter.appendChild(doc.createTextNode(this.compilePageDetailPackage(this._footers)));
        return oddFooter;
      },

      /**
       * This creates some nodes ahead of time, which cuts down on generation time due to
       * most cell definitions being essentially the same, but having multiple nodes that need
       * to be created. Cloning takes less time than creation.
       *
       * @private
       * @param {XML Doc} doc
       * @returns {_L8.Anonym$0._buildCache.Anonym$2}
       */
      _buildCache: function (doc) {
        var numberNode = doc.createElement('c');
        var value = doc.createElement('v');
        value.appendChild(doc.createTextNode("--temp--"));
        numberNode.appendChild(value);

        var formulaNode = doc.createElement('c');
        var formulaValue = doc.createElement('f');
        formulaValue.appendChild(doc.createTextNode("--temp--"));
        formulaNode.appendChild(formulaValue);

        var stringNode = doc.createElement('c');
        stringNode.setAttribute('t', 's');
        var stringValue = doc.createElement('v');
        stringValue.appendChild(doc.createTextNode("--temp--"));
        stringNode.appendChild(stringValue);


        return {
          number: numberNode,
          date: numberNode,
          string: stringNode,
          formula: formulaNode
        };
      },

      /**
       * Runs through the XML document and grabs all of the strings that will
       * be sent to the 'shared strings' document.
       *
       * @returns {Array}
       */
      collectSharedStrings: function () {
        var data = this.data;
        var maxX = 0;
        var strings = {};
        for(var row = 0, l = data.length; row < l; row++) {
          var dataRow = data[row];
          var cellCount = dataRow.length;
          maxX = cellCount > maxX ? cellCount : maxX;
          for(var c = 0; c < cellCount; c++) {
            var cellValue = dataRow[c];
            var metadata = cellValue && cellValue.metadata || {};
            if (cellValue && typeof cellValue === 'object') {
              cellValue = cellValue.value;
            }

            if(!metadata.type) {
              if(typeof cellValue === 'number') {
                metadata.type = 'number';
              }
            }
            if(metadata.type === "text" || !metadata.type) {
              if(typeof strings[cellValue] === 'undefined') {
                strings[cellValue] = true;
              }
            }
          }
        }
        return _.keys(strings);
      },

      toXML: function () {
        var data = this.data;
        var columns = this.columns || [];
        var doc = util.createXmlDoc(util.schemas.spreadsheetml, 'worksheet');
        var worksheet = doc.documentElement;
        var i, l, row;
        worksheet.setAttribute('xmlns:r', util.schemas.relationships);
        worksheet.setAttribute('xmlns:mc', util.schemas.markupCompat);

        var maxX = 0;
        var sheetData = util.createElement(doc, 'sheetData');

        var cellCache = this._buildCache(doc);

        for(row = 0, l = data.length; row < l; row++) {
          var dataRow = data[row];
          var cellCount = dataRow.length;
          maxX = cellCount > maxX ? cellCount : maxX;
          var rowNode = doc.createElement('row');

          for(var c = 0; c < cellCount; c++) {
            columns[c] = columns[c] || {};
            var cellValue = dataRow[c];
            var cell, metadata = cellValue && cellValue.metadata || {};

            if (cellValue && typeof cellValue === 'object') {
              cellValue = cellValue.value;
            }

            if(!metadata.type) {
              if(typeof cellValue === 'number') {
                metadata.type = 'number';
              }
            }

            switch(metadata.type) {
              case "number":
                cell = cellCache.number.cloneNode(true);
                cell.firstChild.firstChild.nodeValue = cellValue;
                break;
              case "date":
                cell = cellCache.date.cloneNode(true);
                cell.firstChild.firstChild.nodeValue = 25569.0 + ((cellValue - this._timezoneOffset)  / (60 * 60 * 24 * 1000));
                break;
              case "formula":
                cell = cellCache.formula.cloneNode(true);
                cell.firstChild.firstChild.nodeValue = cellValue;
                break;
              case "text":
              /*falls through*/
              default:
                var id;
                if(typeof this.sharedStrings.strings[cellValue] !== 'undefined') {
                  id = this.sharedStrings.strings[cellValue];
                } else {
                  id = this.sharedStrings.addString(cellValue);
                }
                cell = cellCache.string.cloneNode(true);
                cell.firstChild.firstChild.nodeValue = id;
                break;
            }
            if(metadata.style) {
              cell.setAttribute('s', metadata.style);
            } else if (this._rowInstructions[row] && this._rowInstructions[row].style !== undefined) {
              cell.setAttribute('s', this._rowInstructions[row].style);
            }
            cell.setAttribute('r', util.positionToLetterRef(c + 1, row + 1));
            rowNode.appendChild(cell);
          }
          rowNode.setAttribute('r', row + 1);

          if (this._rowInstructions[row]) {
            var rowInst = this._rowInstructions[row];

            if (rowInst.height !== undefined) {
              rowNode.setAttribute('customHeight', '1');
              rowNode.setAttribute('ht', rowInst.height);
            }

            if (rowInst.style !== undefined) {
              rowNode.setAttribute('customFormat', '1');
              rowNode.setAttribute('s', rowInst.style);
            }
          }

          sheetData.appendChild(rowNode);
        }

        if(maxX !== 0) {
          worksheet.appendChild(util.createElement(doc, 'dimension', [
            ['ref',  util.positionToLetterRef(1, 1) + ':' + util.positionToLetterRef(maxX, data.length)]
          ]));
        } else {
          worksheet.appendChild(util.createElement(doc, 'dimension', [
            ['ref',  util.positionToLetterRef(1, 1)]
          ]));
        }

        worksheet.appendChild(this.sheetView.exportXML(doc));

        if(this.columns.length) {
          worksheet.appendChild(this.exportColumns(doc));
        }
        worksheet.appendChild(sheetData);

        // The spec doesn't say anything about this, but Excel 2013 requires sheetProtection immediately after sheetData
        if (this.sheetProtection) {
          worksheet.appendChild(this.sheetProtection.exportXML(doc));
        }

        /**
         * Doing this a bit differently, as hyperlinks could be as populous as rows. Looping twice would be bad.
         */
        if(this.hyperlinks.length > 0) {
          var hyperlinksEl = doc.createElement('hyperlinks');
          var hyperlinks = this.hyperlinks;
          for(var i = 0, l = hyperlinks.length; i < l; i++) {
            var hyperlinkEl = doc.createElement('hyperlink'),
              hyperlink = hyperlinks[i];
            hyperlinkEl.setAttribute('ref', hyperlink.cell);
            hyperlink.id = util.uniqueId('hyperlink');
            this.relations.addRelation({
              id: hyperlink.id,
              target: hyperlink.location,
              targetMode: hyperlink.targetMode || 'External'
            }, 'hyperlink');
            hyperlinkEl.setAttribute('r:id', this.relations.getRelationshipId(hyperlink));
            hyperlinksEl.appendChild(hyperlinkEl);
          }
          worksheet.appendChild(hyperlinksEl);
        }

        // 'mergeCells' should be written before 'headerFoot' and 'drawing' due to issue
        // with Microsoft Excel (2007, 2013)
        if (this.mergedCells.length > 0) {
          var mergeCells = doc.createElement('mergeCells');
          for (i = 0, l = this.mergedCells.length; i < l; i++) {
            var mergeCell = doc.createElement('mergeCell');
            mergeCell.setAttribute('ref', this.mergedCells[i][0] + ':' + this.mergedCells[i][1]);
            mergeCells.appendChild(mergeCell);
          }
          worksheet.appendChild(mergeCells);
        }

        this.exportPageSettings(doc, worksheet);

        if(this._headers.length > 0 || this._footers.length > 0) {
          var headerFooter = doc.createElement('headerFooter');
          if(this._headers.length > 0) {
            headerFooter.appendChild(this.exportHeader(doc));
          }
          if(this._footers.length > 0) {
            headerFooter.appendChild(this.exportFooter(doc));
          }
          worksheet.appendChild(headerFooter);
        }

        // the 'drawing' element should be written last, after 'headerFooter', 'mergeCells', etc. due
        // to issue with Microsoft Excel (2007, 2013)
        for(i = 0, l = this._drawings.length; i < l; i++) {
          var drawing = doc.createElement('drawing');
          drawing.setAttribute('r:id', this.relations.getRelationshipId(this._drawings[i]));
          worksheet.appendChild(drawing);
        }

        if(this._tables.length > 0) {
          var tables = doc.createElement('tableParts');
          tables.setAttribute('count', this._tables.length);
          for(i = 0, l = this._tables.length; i < l; i++) {
            var table = doc.createElement('tablePart');
            table.setAttribute('r:id', this.relations.getRelationshipId(this._tables[i]));
            tables.appendChild(table);
          }
          worksheet.appendChild(tables);
        }
        return doc;
      },

      /**
       *
       * @param {XML Doc} doc
       * @returns {XML Node}
       */
      exportColumns: function (doc) {
        var cols = util.createElement(doc, 'cols');
        for(var i = 0, l = this.columns.length; i < l; i++) {
          var cd = this.columns[i];
          var col = util.createElement(doc, 'col', [
            ['min', cd.min || i + 1],
            ['max', cd.max || i + 1]
          ]);
          if (cd.hidden) {
            col.setAttribute('hidden', 1);
          }
          if(cd.bestFit) {
            col.setAttribute('bestFit', 1);
          }
          if(cd.customWidth || cd.width) {
            col.setAttribute('customWidth', 1);
          }
          if(cd.width) {
            col.setAttribute('width', cd.width);
          } else {
            col.setAttribute('width', 9.140625);
          }

          cols.appendChild(col);
        }
        return cols;
      },

      /**
       * Sets the page settings on a worksheet node.
       *
       * @param {XML Doc} doc
       * @param {XML Node} worksheet
       * @returns {undefined}
       */
      exportPageSettings: function (doc, worksheet) {

        if(this._orientation) {
          worksheet.appendChild(util.createElement(doc, 'pageSetup', [
            ['orientation', this._orientation]
          ]));
        }
      },

      /**
       * http://www.schemacentral.com/sc/ooxml/t-ssml_ST_Orientation.html
       *
       * Can be one of 'portrait' or 'landscape'.
       *
       * @param {String} orientation
       * @returns {undefined}
       */
      setPageOrientation: function (orientation) {
        this._orientation = orientation;
      },

      /**
       * Expects an array of column definitions. Each column definition needs to have a width assigned to it.
       *
       * @param {Array} columns
       */
      setColumns: function (columns) {
        this.columns = columns;
      },

      /**
       * Expects an array of data to be translated into cells.
       *
       * @param {Array} data Two dimensional array - [ [A1, A2], [B1, B2] ]
       * @see <a href='/cookbook/addingDataToAWorksheet.html'>Adding data to a worksheet</a>
       */
      setData: function (data) {
        this.data = data;
      },

      /**
       * Merge cells in given range
       *
       * @param cell1 - A1, A2...
       * @param cell2 - A2, A3...
       */
      mergeCells: function(cell1, cell2) {
        this.mergedCells.push([cell1, cell2]);
      },

      /**
       * Added froze pane
       * @param column - column number: 0, 1, 2 ...
       * @param row - row number: 0, 1, 2 ...
       * @param cell - 'A1'
       * @deprecated
       */
      freezePane: function(column, row, cell) {
        this.sheetView.freezePane(column, row, cell);
      },

      /**
       * Expects an array containing an object full of column format definitions.
       * http://msdn.microsoft.com/en-us/library/documentformat.openxml.spreadsheet.column.aspx
       * bestFit
       * collapsed
       * customWidth
       * hidden
       * max
       * min
       * outlineLevel
       * phonetic
       * style
       * width
       * @param {Array} columnFormats
       */
      setColumnFormats: function (columnFormats) {
        this.columnFormats = columnFormats;
      }
    });
    module.exports = Worksheet;

  }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
},{"./RelationshipManager":17,"./SheetView":20,"./util":28}],25:[function(require,module,exports){
  /* jshint strict: false, node: true */
  /* globals  onmessage: true, importScripts, postMessage */
  "use strict";
  var requireConfig;
  var worksheet;
  var start = function(data) {
    require(['Worksheet'], function(Worksheet) {
      worksheet = new Worksheet();
      worksheet.importData(data);
      postMessage({status: 'sharedStrings', data: worksheet.collectSharedStrings()});

    });
  };

  var onmessage = function(event) {
    var data = event.data;
    if (typeof data === 'object') {
      switch (data.instruction) {
        case "setup":
          requireConfig = data.config;
          importScripts(data.requireJsPath);
          require.config(requireConfig);
          postMessage({status: "ready"});
          break;
        case "start":
          start(data.data);
          break;
        case "export":
          worksheet.setSharedStringCollection({
            strings: data.sharedStrings
          });
          postMessage({status: "finished", data: worksheet.toXML().toString()});
          break;
      }
    }
  };




},{}],26:[function(require,module,exports){
  (function (global){
    'use strict';
    var _ = (typeof window !== "undefined" ? window['_'] : typeof global !== "undefined" ? global['_'] : null);

    var XMLDOM = function (ns, rootNodeName) {
      this.documentElement = this.createElement(rootNodeName);
      this.documentElement.setAttribute('xmlns', ns);
    };

    _.extend(XMLDOM.prototype, {
      createElement: function (name) {
        return new XMLDOM.XMLNode({
          nodeName: name
        });
      },
      createTextNode: function (text) {
        return new XMLDOM.TextNode(text);
      },
      toString: function () {
        return this.documentElement.toString();
      }
    });

    XMLDOM.Node = function () {};
    XMLDOM.Node.Create = function (config) {
      switch(config.type) {
        case "XML":
          return new XMLDOM.XMLNode(config);
        case "TEXT":
          return new XMLDOM.TextNode(config.nodeValue);
      }
    };

    XMLDOM.TextNode = function (text) {
      this.nodeValue = text;
    };
    _.extend(XMLDOM.TextNode.prototype, {
      toJSON: function () {
        return {
          nodeValue: this.nodeValue,
          type: 'TEXT'
        };
      },
      toString: function () {
        return _.escape(this.nodeValue);
      }
    });

    XMLDOM.XMLNode = function (config) {
      this.nodeName = config.nodeName;
      this.children = [];
      this.nodeValue = config.nodeValue || "";
      this.attributes = {};

      if(config.children) {
        for(var i = 0, l = config.children.length; i < l; i++) {
          this.appendChild(XMLDOM.Node.Create(config.children[i]));
        }
      }

      if(config.attributes) {
        for(var attr in config.attributes) {
          if(config.attributes.hasOwnProperty(attr)) {
            this.setAttribute(attr, config.attributes[attr]);
          }
        }
      }
    };
    _.extend(XMLDOM.XMLNode.prototype, {

      toString: function () {
        var string = "<" + this.nodeName;
        for(var attr in this.attributes) {
          if(this.attributes.hasOwnProperty(attr)) {
            string = string + " " + attr + "=\""+_.escape(this.attributes[attr])+"\"";
          }
        }

        var childContent = "";
        for(var i = 0, l = this.children.length; i < l; i++) {
          childContent += this.children[i].toString();
        }

        if (childContent){
          string +=  ">" + childContent + "</" + this.nodeName + ">";
        } else {
          string += "/>";
        }

        return string;
      },

      toJSON: function () {
        var children = [];
        for(var i = 0, l = this.children.length; i < l; i++) {
          children.push(this.children[i].toJSON());
        }
        return {
          nodeName: this.nodeName,
          children: children,
          nodeValue: this.nodeValue,
          attributes: this.attributes,
          type: "XML"
        };
      },

      setAttribute: function (name, val) {
        if(val === null) {
          delete this.attributes[name];
          delete this[name];
          return;
        }
        this.attributes[name] = val;
        this[name] = val;
      },
      appendChild: function (child) {
        this.children.push(child);
        this.firstChild = this.children[0];
      },
      cloneNode: function () {
        return new XMLDOM.XMLNode(this.toJSON());
      }
    });

    module.exports = XMLDOM;
  }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
},{}],27:[function(require,module,exports){
  /* jshint unused: false */
  /* globals  importScripts, JSZip, postMessage */

  var onmessage = function(event) {
    "use strict";
    if (!event.data || !event.data.ziplib) { return; }

    importScripts(event.data.ziplib);

    var zip = new JSZip();
    var files = event.data.files;
    for(var path in files) {
      if(files.hasOwnProperty(path)) {
        var content = files[path];
        path = path.substr(1);
        zip.file(path, content, {base64: false});
      }
    }
    postMessage({
      base64: !!event.data.base64
    });
    postMessage({
      status: 'done',
      data: zip.generate({
        base64: !!event.data.base64
      })
    });
  };




},{}],28:[function(require,module,exports){
  (function (global){
    "use strict";
    var XMLDOM = require('./XMLDOM');
    var _ = (typeof window !== "undefined" ? window['_'] : typeof global !== "undefined" ? global['_'] : null);
    /**
     * @module Excel/util
     */

    var util = {

      _idSpaces: {},

      /**
       * Returns a number based on a namespace. So, running with 'Picture' will return 1. Run again, you will get 2. Run with 'Foo', you'll get 1.
       * @param {String} space
       * @returns {Number}
       */
      uniqueId: function (space) {
        if(!this._idSpaces[space]) {
          this._idSpaces[space] = 1;
        }
        return this._idSpaces[space]++;
      },

      /**
       * Attempts to create an XML document. After some investigation, using the 'fake' document
       * is significantly faster than creating an actual XML document, so we're going to go with
       * that. Besides, it just makes it easier to port to node.
       *
       * Takes a namespace to start the xml file in, as well as the root element
       * of the xml file.
       *
       * @param {type} ns
       * @param {type} base
       * @returns {@new;XMLDOM}
       */
      createXmlDoc: function (ns, base) {
        return new XMLDOM(ns || null, base, null);
      },

      /**
       * Creates an xml node (element). Used to simplify some calls, as IE is
       * very particular about namespaces and such.
       *
       * @param {XMLDOM} doc An xml document (actual DOM or fake DOM, not a string)
       * @param {type} name The name of the element
       * @param {type} attributes
       * @returns {XML Node}
       */
      createElement: function (doc, name, attributes) {
        var el = doc.createElement(name);
        attributes = attributes || [];
        var i = attributes.length;
        while (i--) {
          el.setAttribute(attributes[i][0], attributes[i][1]);
        }
        return el;
      },

      /**
       * This is sort of slow, but it's a huge convenience method for the code. It probably shouldn't be used
       * in high repetition areas.
       *
       * @param {XMLDoc} doc
       * @param {Object} attrs
       */
      setAttributesOnDoc: function (doc, attrs) {
        _.forEach(attrs, function (v, k) {
          if(_.isPlainObject(v)) {
            if(v.v !== null && v.v !== undefined) {
              switch(v.type) {
                case Boolean:
                  v = v.v ? '1' : '0';
                  break;
              }
            } else {
              v = null;
            }
          }
          if(v !== null && v !== undefined) {
            doc.setAttribute(k, v);
          }
        })
      },

      LETTER_REFS: {},

      positionToLetterRef: function (x, y) {
        var digit = 1, index, num = x, string = "", alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
        if(this.LETTER_REFS[x]) {
          return this.LETTER_REFS[x].concat(y);
        }
        while (num > 0) {
          num -= Math.pow(26, digit -1);
          index = num % Math.pow(26, digit);
          num -= index;
          index = index / Math.pow(26, digit - 1);
          string = alphabet.charAt(index) + string;
          digit += 1;
        }
        this.LETTER_REFS[x] = string;
        return string.concat(y);
      },

      schemas: {
        'worksheet': 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet',
        'sharedStrings': "http://schemas.openxmlformats.org/officeDocument/2006/relationships/sharedStrings",
        'stylesheet': "http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles",
        'relationships': 'http://schemas.openxmlformats.org/officeDocument/2006/relationships',
        'relationshipPackage': "http://schemas.openxmlformats.org/package/2006/relationships",
        'contentTypes': "http://schemas.openxmlformats.org/package/2006/content-types",
        'spreadsheetml': "http://schemas.openxmlformats.org/spreadsheetml/2006/main",
        'markupCompat': "http://schemas.openxmlformats.org/markup-compatibility/2006",
        'x14ac': "http://schemas.microsoft.com/office/spreadsheetml/2009/9/ac",
        'officeDocument': "http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument",
        'package': "http://schemas.openxmlformats.org/package/2006/relationships",
        'table': "http://schemas.openxmlformats.org/officeDocument/2006/relationships/table",
        'spreadsheetDrawing': 'http://schemas.openxmlformats.org/drawingml/2006/spreadsheetDrawing',
        'drawing': 'http://schemas.openxmlformats.org/drawingml/2006/main',
        'drawingRelationship': 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/drawing',
        'image': 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/image',
        'chart': 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/chart',
        'hyperlink': "http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink"
      }
    };

    module.exports = util;
  }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
},{"./XMLDOM":26}],29:[function(require,module,exports){
  (function (global){
    'use strict';

    var Workbook = require('../Excel/Workbook');
    var Table = require('../Excel/Table');
    var _ = (typeof window !== "undefined" ? window['_'] : typeof global !== "undefined" ? global['_'] : null);

    var Template = function (worksheetConstructorSettings) {
      this.workbook = new Workbook();
      this.stylesheet = this.workbook.getStyleSheet();

      this.columns = {};

      this.predefinedStyles = {

      };

      this.predefinedFormatters = {
        date: this.stylesheet.createSimpleFormatter('date'),
        currency: this.stylesheet.createFormat({format: "$ #,##0.00;$ #,##0.00;-", font: {color: "FFE9F50A"}}),
        header: this.stylesheet.createFormat({
          font: { bold: true, underline: true, color: {theme: 3}},
          alignment: {horizontal: 'center'}
        })
      };

      if(worksheetConstructorSettings != null) {
        this.worksheet = this.workbook.createWorksheet(worksheetConstructorSettings);
      }
      else {
        this.worksheet = this.workbook.createWorksheet();
      }
      this.workbook.addWorksheet(this.worksheet);
      this.worksheet.setPageOrientation('landscape');
      this.table = new Table();
      this.table.styleInfo.themeStyle = "TableStyleLight1";
      this.worksheet.addTable(this.table);
      this.workbook.addTable(this.table);
    };

    _.extend(Template.prototype, {
      setHeader: function () {
        this.worksheet.setHeader.apply(this.worksheet, arguments);
      },
      setFooter: function () {
        this.worksheet.setFooter.apply(this.worksheet, arguments);
      },
      prepare: function () {
        return this.workbook;
      },

      setData: function (worksheetData) {
        this.worksheet.setData(worksheetData);
        this.data = worksheetData;
        this.table.setReferenceRange([1, 1], [this.columns.length, worksheetData.length]);
      },

      setColumns: function (columns) {
        this.columns = columns;
        this.worksheet.setColumns(columns);
        this.table.setTableColumns(columns);
        this.table.setReferenceRange([1, 1], [this.columns.length, this.data.length]);
      },

      getWorksheet: function () {
        return this.worksheet;
      }
    });

    module.exports = Template;

  }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
},{"../Excel/Table":22,"../Excel/Workbook":23}],30:[function(require,module,exports){
  module.exports = {
    BasicReport: require('./BasicReport')
  };
},{"./BasicReport":29}],31:[function(require,module,exports){
  (function (global){
    "use strict";
    var _ = (typeof window !== "undefined" ? window['_'] : typeof global !== "undefined" ? global['_'] : null);
    var Workbook = require('./Excel/Workbook');
    var JSZip = (typeof window !== "undefined" ? window['JSZip'] : typeof global !== "undefined" ? global['JSZip'] : null);
//var WorkbookWorker = require('./Worker');

    /**
     * @name Excel
     * @public
     * @author Stephen Liberty
     * @requires underscore
     * @requires Excel/Workbook
     * @requires JSZIP
     * @exports excel-builder
     */
    var Factory = {
      /**
       * Creates a new workbook.
       */
      createWorkbook: function () {
        return new Workbook();
      },

      config: {
        forceUIThread: false
      },

      /**
       * Turns a workbook into a downloadable file.
       * @param {Excel/Workbook} workbook The workbook that is being converted
       * @param {Object} options
       * @param {Boolean} options.base64 Whether to 'return' the generated file as a base64 string
       * @param {Function} options.success The callback function to run after workbook creation is successful.
       * @param {Function} options.error The callback function to run if there is an error creating the workbook.
       * @param {String} options.requireJsPath (Optional) The path to requirejs. Will use the id 'requirejs' to look up the script if not specified.
       */
      createFileAsync: function (workbook, options) {


        workbook.generateFilesAsync({
          success: function (files) {

            var worker = new Worker(require.toUrl('./Excel/ZipWorker.js'));
            worker.addEventListener('message', function(event) {
              if(event.data.status === 'done') {
                options.success(event.data.data);
              }
            });
            worker.postMessage({
              files: files,
              ziplib: require.toUrl('JSZip'),
              base64: (!options || options.base64 !== false)
            });
          },
          error: function () {
            options.error();
          }
        });
      },

      /**
       * Turns a workbook into a downloadable file.
       * @param {Excel/Workbook} workbook The workbook that is being converted
       * @param {Object} options - options to modify how the zip is created. See http://stuk.github.io/jszip/#doc_generate_options
       * @returns {Promise}
       */
      createFile: function (workbook, options) {
        var zip = new JSZip();
        return workbook.generateFiles().then(function (files) {
          _.each(files, function (content, path) {
            path = path.substr(1);
            if(path.indexOf('.xml') !== -1 || path.indexOf('.rel') !== -1) {
              zip.file(path, content, {base64: false});
            } else {
              zip.file(path, content, {base64: true, binary: true});
            }
          });
          return zip.generate(_.defaults(options || {}, {
            type: "base64"
          }));
        });
      }
    };


    module.exports = Factory;
  }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
},{"./Excel/Workbook":23}],32:[function(require,module,exports){
  (function (global){
    var _ = (typeof window !== "undefined" ? window['_'] : typeof global !== "undefined" ? global['_'] : null);
    var EBExport = module.exports = {
      Drawings: require('./Excel/Drawings'),
      Drawing: require('./Excel/Drawing/index'),
      Pane: require('./Excel/Pane'),
      Paths: require('./Excel/Paths'),
      Positioning: require('./Excel/Positioning'),
      RelationshipManager: require('./Excel/RelationshipManager'),
      SharedStrings: require('./Excel/SharedStrings'),
      SheetProtection: require('./Excel/SheetProtection'),
      SheetView: require('./Excel/SheetView'),
      StyleSheet: require('./Excel/StyleSheet'),
      Table: require('./Excel/Table'),
      util: require('./Excel/util'),
      Workbook: require('./Excel/Workbook'),
      Worksheet: require('./Excel/Worksheet'),
      WorksheetExportWorker: require('./Excel/WorksheetExportWorker'),
      XMLDOM: require('./Excel/XMLDOM'),
      ZipWorker: require('./Excel/ZipWorker'),
      Builder: require('./excel-builder'),
      Template: require('./Template')
    };

    try {
      if(typeof window !== 'undefined!') {
        window.ExcelBuilder = EBExport;
      }
    } catch (e) {
      //Silently ignore?
      console.info("Not attaching EB to window");
    }
  }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
},{"./Excel/Drawing/index":12,"./Excel/Drawings":13,"./Excel/Pane":14,"./Excel/Paths":15,"./Excel/Positioning":16,"./Excel/RelationshipManager":17,"./Excel/SharedStrings":18,"./Excel/SheetProtection":19,"./Excel/SheetView":20,"./Excel/StyleSheet":21,"./Excel/Table":22,"./Excel/Workbook":23,"./Excel/Worksheet":24,"./Excel/WorksheetExportWorker":25,"./Excel/XMLDOM":26,"./Excel/ZipWorker":27,"./Excel/util":28,"./Template":30,"./excel-builder":31}],"q":[function(require,module,exports){
  (function (process){
// vim:ts=4:sts=4:sw=4:
    /*!
     *
     * Copyright 2009-2012 Kris Kowal under the terms of the MIT
     * license found at http://github.com/kriskowal/q/raw/master/LICENSE
     *
     * With parts by Tyler Close
     * Copyright 2007-2009 Tyler Close under the terms of the MIT X license found
     * at http://www.opensource.org/licenses/mit-license.html
     * Forked at ref_send.js version: 2009-05-11
     *
     * With parts by Mark Miller
     * Copyright (C) 2011 Google Inc.
     *
     * Licensed under the Apache License, Version 2.0 (the "License");
     * you may not use this file except in compliance with the License.
     * You may obtain a copy of the License at
     *
     * http://www.apache.org/licenses/LICENSE-2.0
     *
     * Unless required by applicable law or agreed to in writing, software
     * distributed under the License is distributed on an "AS IS" BASIS,
     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     * See the License for the specific language governing permissions and
     * limitations under the License.
     *
     */

    (function (definition) {
      "use strict";

      // This file will function properly as a <script> tag, or a module
      // using CommonJS and NodeJS or RequireJS module formats.  In
      // Common/Node/RequireJS, the module exports the Q API and when
      // executed as a simple <script>, it creates a Q global instead.

      // Montage Require
      if (typeof bootstrap === "function") {
        bootstrap("promise", definition);

        // CommonJS
      } else if (typeof exports === "object" && typeof module === "object") {
        module.exports = definition();

        // RequireJS
      } else if (typeof define === "function" && define.amd) {
        define(definition);

        // SES (Secure EcmaScript)
      } else if (typeof ses !== "undefined") {
        if (!ses.ok()) {
          return;
        } else {
          ses.makeQ = definition;
        }

        // <script>
      } else if (typeof window !== "undefined" || typeof self !== "undefined") {
        // Prefer window over self for add-on scripts. Use self for
        // non-windowed contexts.
        var global = typeof window !== "undefined" ? window : self;

        // Get the `window` object, save the previous Q global
        // and initialize Q as a global.
        var previousQ = global.Q;
        global.Q = definition();

        // Add a noConflict function so Q can be removed from the
        // global namespace.
        global.Q.noConflict = function () {
          global.Q = previousQ;
          return this;
        };

      } else {
        throw new Error("This environment was not anticipated by Q. Please file a bug.");
      }

    })(function () {
      "use strict";

      var hasStacks = false;
      try {
        throw new Error();
      } catch (e) {
        hasStacks = !!e.stack;
      }

// All code after this point will be filtered from stack traces reported
// by Q.
      var qStartingLine = captureLine();
      var qFileName;

// shims

// used for fallback in "allResolved"
      var noop = function () {};

// Use the fastest possible means to execute a task in a future turn
// of the event loop.
      var nextTick =(function () {
        // linked list of tasks (single, with head node)
        var head = {task: void 0, next: null};
        var tail = head;
        var flushing = false;
        var requestTick = void 0;
        var isNodeJS = false;
        // queue for late tasks, used by unhandled rejection tracking
        var laterQueue = [];

        function flush() {
          /* jshint loopfunc: true */
          var task, domain;

          while (head.next) {
            head = head.next;
            task = head.task;
            head.task = void 0;
            domain = head.domain;

            if (domain) {
              head.domain = void 0;
              domain.enter();
            }
            runSingle(task, domain);

          }
          while (laterQueue.length) {
            task = laterQueue.pop();
            runSingle(task);
          }
          flushing = false;
        }
        // runs a single function in the async queue
        function runSingle(task, domain) {
          try {
            task();

          } catch (e) {
            if (isNodeJS) {
              // In node, uncaught exceptions are considered fatal errors.
              // Re-throw them synchronously to interrupt flushing!

              // Ensure continuation if the uncaught exception is suppressed
              // listening "uncaughtException" events (as domains does).
              // Continue in next event to avoid tick recursion.
              if (domain) {
                domain.exit();
              }
              setTimeout(flush, 0);
              if (domain) {
                domain.enter();
              }

              throw e;

            } else {
              // In browsers, uncaught exceptions are not fatal.
              // Re-throw them asynchronously to avoid slow-downs.
              setTimeout(function () {
                throw e;
              }, 0);
            }
          }

          if (domain) {
            domain.exit();
          }
        }

        nextTick = function (task) {
          tail = tail.next = {
            task: task,
            domain: isNodeJS && process.domain,
            next: null
          };

          if (!flushing) {
            flushing = true;
            requestTick();
          }
        };

        if (typeof process === "object" &&
          process.toString() === "[object process]" && process.nextTick) {
          // Ensure Q is in a real Node environment, with a `process.nextTick`.
          // To see through fake Node environments:
          // * Mocha test runner - exposes a `process` global without a `nextTick`
          // * Browserify - exposes a `process.nexTick` function that uses
          //   `setTimeout`. In this case `setImmediate` is preferred because
          //    it is faster. Browserify's `process.toString()` yields
          //   "[object Object]", while in a real Node environment
          //   `process.nextTick()` yields "[object process]".
          isNodeJS = true;

          requestTick = function () {
            process.nextTick(flush);
          };

        } else if (typeof setImmediate === "function") {
          // In IE10, Node.js 0.9+, or https://github.com/NobleJS/setImmediate
          if (typeof window !== "undefined") {
            requestTick = setImmediate.bind(window, flush);
          } else {
            requestTick = function () {
              setImmediate(flush);
            };
          }

        } else if (typeof MessageChannel !== "undefined") {
          // modern browsers
          // http://www.nonblocking.io/2011/06/windownexttick.html
          var channel = new MessageChannel();
          // At least Safari Version 6.0.5 (8536.30.1) intermittently cannot create
          // working message ports the first time a page loads.
          channel.port1.onmessage = function () {
            requestTick = requestPortTick;
            channel.port1.onmessage = flush;
            flush();
          };
          var requestPortTick = function () {
            // Opera requires us to provide a message payload, regardless of
            // whether we use it.
            channel.port2.postMessage(0);
          };
          requestTick = function () {
            setTimeout(flush, 0);
            requestPortTick();
          };

        } else {
          // old browsers
          requestTick = function () {
            setTimeout(flush, 0);
          };
        }
        // runs a task after all other tasks have been run
        // this is useful for unhandled rejection tracking that needs to happen
        // after all `then`d tasks have been run.
        nextTick.runAfter = function (task) {
          laterQueue.push(task);
          if (!flushing) {
            flushing = true;
            requestTick();
          }
        };
        return nextTick;
      })();

// Attempt to make generics safe in the face of downstream
// modifications.
// There is no situation where this is necessary.
// If you need a security guarantee, these primordials need to be
// deeply frozen anyway, and if you don’t need a security guarantee,
// this is just plain paranoid.
// However, this **might** have the nice side-effect of reducing the size of
// the minified code by reducing x.call() to merely x()
// See Mark Miller’s explanation of what this does.
// http://wiki.ecmascript.org/doku.php?id=conventions:safe_meta_programming
      var call = Function.call;
      function uncurryThis(f) {
        return function () {
          return call.apply(f, arguments);
        };
      }
// This is equivalent, but slower:
// uncurryThis = Function_bind.bind(Function_bind.call);
// http://jsperf.com/uncurrythis

      var array_slice = uncurryThis(Array.prototype.slice);

      var array_reduce = uncurryThis(
        Array.prototype.reduce || function (callback, basis) {
          var index = 0,
            length = this.length;
          // concerning the initial value, if one is not provided
          if (arguments.length === 1) {
            // seek to the first value in the array, accounting
            // for the possibility that is is a sparse array
            do {
              if (index in this) {
                basis = this[index++];
                break;
              }
              if (++index >= length) {
                throw new TypeError();
              }
            } while (1);
          }
          // reduce
          for (; index < length; index++) {
            // account for the possibility that the array is sparse
            if (index in this) {
              basis = callback(basis, this[index], index);
            }
          }
          return basis;
        }
      );

      var array_indexOf = uncurryThis(
        Array.prototype.indexOf || function (value) {
          // not a very good shim, but good enough for our one use of it
          for (var i = 0; i < this.length; i++) {
            if (this[i] === value) {
              return i;
            }
          }
          return -1;
        }
      );

      var array_map = uncurryThis(
        Array.prototype.map || function (callback, thisp) {
          var self = this;
          var collect = [];
          array_reduce(self, function (undefined, value, index) {
            collect.push(callback.call(thisp, value, index, self));
          }, void 0);
          return collect;
        }
      );

      var object_create = Object.create || function (prototype) {
          function Type() { }
          Type.prototype = prototype;
          return new Type();
        };

      var object_hasOwnProperty = uncurryThis(Object.prototype.hasOwnProperty);

      var object_keys = Object.keys || function (object) {
          var keys = [];
          for (var key in object) {
            if (object_hasOwnProperty(object, key)) {
              keys.push(key);
            }
          }
          return keys;
        };

      var object_toString = uncurryThis(Object.prototype.toString);

      function isObject(value) {
        return value === Object(value);
      }

// generator related shims

// FIXME: Remove this function once ES6 generators are in SpiderMonkey.
      function isStopIteration(exception) {
        return (
          object_toString(exception) === "[object StopIteration]" ||
          exception instanceof QReturnValue
        );
      }

// FIXME: Remove this helper and Q.return once ES6 generators are in
// SpiderMonkey.
      var QReturnValue;
      if (typeof ReturnValue !== "undefined") {
        QReturnValue = ReturnValue;
      } else {
        QReturnValue = function (value) {
          this.value = value;
        };
      }

// long stack traces

      var STACK_JUMP_SEPARATOR = "From previous event:";

      function makeStackTraceLong(error, promise) {
        // If possible, transform the error stack trace by removing Node and Q
        // cruft, then concatenating with the stack trace of `promise`. See #57.
        if (hasStacks &&
          promise.stack &&
          typeof error === "object" &&
          error !== null &&
          error.stack &&
          error.stack.indexOf(STACK_JUMP_SEPARATOR) === -1
        ) {
          var stacks = [];
          for (var p = promise; !!p; p = p.source) {
            if (p.stack) {
              stacks.unshift(p.stack);
            }
          }
          stacks.unshift(error.stack);

          var concatedStacks = stacks.join("\n" + STACK_JUMP_SEPARATOR + "\n");
          error.stack = filterStackString(concatedStacks);
        }
      }

      function filterStackString(stackString) {
        var lines = stackString.split("\n");
        var desiredLines = [];
        for (var i = 0; i < lines.length; ++i) {
          var line = lines[i];

          if (!isInternalFrame(line) && !isNodeFrame(line) && line) {
            desiredLines.push(line);
          }
        }
        return desiredLines.join("\n");
      }

      function isNodeFrame(stackLine) {
        return stackLine.indexOf("(module.js:") !== -1 ||
          stackLine.indexOf("(node.js:") !== -1;
      }

      function getFileNameAndLineNumber(stackLine) {
        // Named functions: "at functionName (filename:lineNumber:columnNumber)"
        // In IE10 function name can have spaces ("Anonymous function") O_o
        var attempt1 = /at .+ \((.+):(\d+):(?:\d+)\)$/.exec(stackLine);
        if (attempt1) {
          return [attempt1[1], Number(attempt1[2])];
        }

        // Anonymous functions: "at filename:lineNumber:columnNumber"
        var attempt2 = /at ([^ ]+):(\d+):(?:\d+)$/.exec(stackLine);
        if (attempt2) {
          return [attempt2[1], Number(attempt2[2])];
        }

        // Firefox style: "function@filename:lineNumber or @filename:lineNumber"
        var attempt3 = /.*@(.+):(\d+)$/.exec(stackLine);
        if (attempt3) {
          return [attempt3[1], Number(attempt3[2])];
        }
      }

      function isInternalFrame(stackLine) {
        var fileNameAndLineNumber = getFileNameAndLineNumber(stackLine);

        if (!fileNameAndLineNumber) {
          return false;
        }

        var fileName = fileNameAndLineNumber[0];
        var lineNumber = fileNameAndLineNumber[1];

        return fileName === qFileName &&
          lineNumber >= qStartingLine &&
          lineNumber <= qEndingLine;
      }

// discover own file name and line number range for filtering stack
// traces
      function captureLine() {
        if (!hasStacks) {
          return;
        }

        try {
          throw new Error();
        } catch (e) {
          var lines = e.stack.split("\n");
          var firstLine = lines[0].indexOf("@") > 0 ? lines[1] : lines[2];
          var fileNameAndLineNumber = getFileNameAndLineNumber(firstLine);
          if (!fileNameAndLineNumber) {
            return;
          }

          qFileName = fileNameAndLineNumber[0];
          return fileNameAndLineNumber[1];
        }
      }

      function deprecate(callback, name, alternative) {
        return function () {
          if (typeof console !== "undefined" &&
            typeof console.warn === "function") {
            console.warn(name + " is deprecated, use " + alternative +
              " instead.", new Error("").stack);
          }
          return callback.apply(callback, arguments);
        };
      }

// end of shims
// beginning of real work

      /**
       * Constructs a promise for an immediate reference, passes promises through, or
       * coerces promises from different systems.
       * @param value immediate reference or promise
       */
      function Q(value) {
        // If the object is already a Promise, return it directly.  This enables
        // the resolve function to both be used to created references from objects,
        // but to tolerably coerce non-promises to promises.
        if (value instanceof Promise) {
          return value;
        }

        // assimilate thenables
        if (isPromiseAlike(value)) {
          return coerce(value);
        } else {
          return fulfill(value);
        }
      }
      Q.resolve = Q;

      /**
       * Performs a task in a future turn of the event loop.
       * @param {Function} task
       */
      Q.nextTick = nextTick;

      /**
       * Controls whether or not long stack traces will be on
       */
      Q.longStackSupport = false;

// enable long stacks if Q_DEBUG is set
      if (typeof process === "object" && process && process.env && process.env.Q_DEBUG) {
        Q.longStackSupport = true;
      }

      /**
       * Constructs a {promise, resolve, reject} object.
       *
       * `resolve` is a callback to invoke with a more resolved value for the
       * promise. To fulfill the promise, invoke `resolve` with any value that is
       * not a thenable. To reject the promise, invoke `resolve` with a rejected
       * thenable, or invoke `reject` with the reason directly. To resolve the
       * promise to another thenable, thus putting it in the same state, invoke
       * `resolve` with that other thenable.
       */
      Q.defer = defer;
      function defer() {
        // if "messages" is an "Array", that indicates that the promise has not yet
        // been resolved.  If it is "undefined", it has been resolved.  Each
        // element of the messages array is itself an array of complete arguments to
        // forward to the resolved promise.  We coerce the resolution value to a
        // promise using the `resolve` function because it handles both fully
        // non-thenable values and other thenables gracefully.
        var messages = [], progressListeners = [], resolvedPromise;

        var deferred = object_create(defer.prototype);
        var promise = object_create(Promise.prototype);

        promise.promiseDispatch = function (resolve, op, operands) {
          var args = array_slice(arguments);
          if (messages) {
            messages.push(args);
            if (op === "when" && operands[1]) { // progress operand
              progressListeners.push(operands[1]);
            }
          } else {
            Q.nextTick(function () {
              resolvedPromise.promiseDispatch.apply(resolvedPromise, args);
            });
          }
        };

        // XXX deprecated
        promise.valueOf = function () {
          if (messages) {
            return promise;
          }
          var nearerValue = nearer(resolvedPromise);
          if (isPromise(nearerValue)) {
            resolvedPromise = nearerValue; // shorten chain
          }
          return nearerValue;
        };

        promise.inspect = function () {
          if (!resolvedPromise) {
            return { state: "pending" };
          }
          return resolvedPromise.inspect();
        };

        if (Q.longStackSupport && hasStacks) {
          try {
            throw new Error();
          } catch (e) {
            // NOTE: don't try to use `Error.captureStackTrace` or transfer the
            // accessor around; that causes memory leaks as per GH-111. Just
            // reify the stack trace as a string ASAP.
            //
            // At the same time, cut off the first line; it's always just
            // "[object Promise]\n", as per the `toString`.
            promise.stack = e.stack.substring(e.stack.indexOf("\n") + 1);
          }
        }

        // NOTE: we do the checks for `resolvedPromise` in each method, instead of
        // consolidating them into `become`, since otherwise we'd create new
        // promises with the lines `become(whatever(value))`. See e.g. GH-252.

        function become(newPromise) {
          resolvedPromise = newPromise;
          promise.source = newPromise;

          array_reduce(messages, function (undefined, message) {
            Q.nextTick(function () {
              newPromise.promiseDispatch.apply(newPromise, message);
            });
          }, void 0);

          messages = void 0;
          progressListeners = void 0;
        }

        deferred.promise = promise;
        deferred.resolve = function (value) {
          if (resolvedPromise) {
            return;
          }

          become(Q(value));
        };

        deferred.fulfill = function (value) {
          if (resolvedPromise) {
            return;
          }

          become(fulfill(value));
        };
        deferred.reject = function (reason) {
          if (resolvedPromise) {
            return;
          }

          become(reject(reason));
        };
        deferred.notify = function (progress) {
          if (resolvedPromise) {
            return;
          }

          array_reduce(progressListeners, function (undefined, progressListener) {
            Q.nextTick(function () {
              progressListener(progress);
            });
          }, void 0);
        };

        return deferred;
      }

      /**
       * Creates a Node-style callback that will resolve or reject the deferred
       * promise.
       * @returns a nodeback
       */
      defer.prototype.makeNodeResolver = function () {
        var self = this;
        return function (error, value) {
          if (error) {
            self.reject(error);
          } else if (arguments.length > 2) {
            self.resolve(array_slice(arguments, 1));
          } else {
            self.resolve(value);
          }
        };
      };

      /**
       * @param resolver {Function} a function that returns nothing and accepts
       * the resolve, reject, and notify functions for a deferred.
       * @returns a promise that may be resolved with the given resolve and reject
       * functions, or rejected by a thrown exception in resolver
       */
      Q.Promise = promise; // ES6
      Q.promise = promise;
      function promise(resolver) {
        if (typeof resolver !== "function") {
          throw new TypeError("resolver must be a function.");
        }
        var deferred = defer();
        try {
          resolver(deferred.resolve, deferred.reject, deferred.notify);
        } catch (reason) {
          deferred.reject(reason);
        }
        return deferred.promise;
      }

      promise.race = race; // ES6
      promise.all = all; // ES6
      promise.reject = reject; // ES6
      promise.resolve = Q; // ES6

// XXX experimental.  This method is a way to denote that a local value is
// serializable and should be immediately dispatched to a remote upon request,
// instead of passing a reference.
      Q.passByCopy = function (object) {
        //freeze(object);
        //passByCopies.set(object, true);
        return object;
      };

      Promise.prototype.passByCopy = function () {
        //freeze(object);
        //passByCopies.set(object, true);
        return this;
      };

      /**
       * If two promises eventually fulfill to the same value, promises that value,
       * but otherwise rejects.
       * @param x {Any*}
       * @param y {Any*}
       * @returns {Any*} a promise for x and y if they are the same, but a rejection
       * otherwise.
       *
       */
      Q.join = function (x, y) {
        return Q(x).join(y);
      };

      Promise.prototype.join = function (that) {
        return Q([this, that]).spread(function (x, y) {
          if (x === y) {
            // TODO: "===" should be Object.is or equiv
            return x;
          } else {
            throw new Error("Can't join: not the same: " + x + " " + y);
          }
        });
      };

      /**
       * Returns a promise for the first of an array of promises to become settled.
       * @param answers {Array[Any*]} promises to race
       * @returns {Any*} the first promise to be settled
       */
      Q.race = race;
      function race(answerPs) {
        return promise(function (resolve, reject) {
          // Switch to this once we can assume at least ES5
          // answerPs.forEach(function (answerP) {
          //     Q(answerP).then(resolve, reject);
          // });
          // Use this in the meantime
          for (var i = 0, len = answerPs.length; i < len; i++) {
            Q(answerPs[i]).then(resolve, reject);
          }
        });
      }

      Promise.prototype.race = function () {
        return this.then(Q.race);
      };

      /**
       * Constructs a Promise with a promise descriptor object and optional fallback
       * function.  The descriptor contains methods like when(rejected), get(name),
       * set(name, value), post(name, args), and delete(name), which all
       * return either a value, a promise for a value, or a rejection.  The fallback
       * accepts the operation name, a resolver, and any further arguments that would
       * have been forwarded to the appropriate method above had a method been
       * provided with the proper name.  The API makes no guarantees about the nature
       * of the returned object, apart from that it is usable whereever promises are
       * bought and sold.
       */
      Q.makePromise = Promise;
      function Promise(descriptor, fallback, inspect) {
        if (fallback === void 0) {
          fallback = function (op) {
            return reject(new Error(
              "Promise does not support operation: " + op
            ));
          };
        }
        if (inspect === void 0) {
          inspect = function () {
            return {state: "unknown"};
          };
        }

        var promise = object_create(Promise.prototype);

        promise.promiseDispatch = function (resolve, op, args) {
          var result;
          try {
            if (descriptor[op]) {
              result = descriptor[op].apply(promise, args);
            } else {
              result = fallback.call(promise, op, args);
            }
          } catch (exception) {
            result = reject(exception);
          }
          if (resolve) {
            resolve(result);
          }
        };

        promise.inspect = inspect;

        // XXX deprecated `valueOf` and `exception` support
        if (inspect) {
          var inspected = inspect();
          if (inspected.state === "rejected") {
            promise.exception = inspected.reason;
          }

          promise.valueOf = function () {
            var inspected = inspect();
            if (inspected.state === "pending" ||
              inspected.state === "rejected") {
              return promise;
            }
            return inspected.value;
          };
        }

        return promise;
      }

      Promise.prototype.toString = function () {
        return "[object Promise]";
      };

      Promise.prototype.then = function (fulfilled, rejected, progressed) {
        var self = this;
        var deferred = defer();
        var done = false;   // ensure the untrusted promise makes at most a
                            // single call to one of the callbacks

        function _fulfilled(value) {
          try {
            return typeof fulfilled === "function" ? fulfilled(value) : value;
          } catch (exception) {
            return reject(exception);
          }
        }

        function _rejected(exception) {
          if (typeof rejected === "function") {
            makeStackTraceLong(exception, self);
            try {
              return rejected(exception);
            } catch (newException) {
              return reject(newException);
            }
          }
          return reject(exception);
        }

        function _progressed(value) {
          return typeof progressed === "function" ? progressed(value) : value;
        }

        Q.nextTick(function () {
          self.promiseDispatch(function (value) {
            if (done) {
              return;
            }
            done = true;

            deferred.resolve(_fulfilled(value));
          }, "when", [function (exception) {
            if (done) {
              return;
            }
            done = true;

            deferred.resolve(_rejected(exception));
          }]);
        });

        // Progress propagator need to be attached in the current tick.
        self.promiseDispatch(void 0, "when", [void 0, function (value) {
          var newValue;
          var threw = false;
          try {
            newValue = _progressed(value);
          } catch (e) {
            threw = true;
            if (Q.onerror) {
              Q.onerror(e);
            } else {
              throw e;
            }
          }

          if (!threw) {
            deferred.notify(newValue);
          }
        }]);

        return deferred.promise;
      };

      Q.tap = function (promise, callback) {
        return Q(promise).tap(callback);
      };

      /**
       * Works almost like "finally", but not called for rejections.
       * Original resolution value is passed through callback unaffected.
       * Callback may return a promise that will be awaited for.
       * @param {Function} callback
       * @returns {Q.Promise}
       * @example
       * doSomething()
       *   .then(...)
       *   .tap(console.log)
       *   .then(...);
       */
      Promise.prototype.tap = function (callback) {
        callback = Q(callback);

        return this.then(function (value) {
          return callback.fcall(value).thenResolve(value);
        });
      };

      /**
       * Registers an observer on a promise.
       *
       * Guarantees:
       *
       * 1. that fulfilled and rejected will be called only once.
       * 2. that either the fulfilled callback or the rejected callback will be
       *    called, but not both.
       * 3. that fulfilled and rejected will not be called in this turn.
       *
       * @param value      promise or immediate reference to observe
       * @param fulfilled  function to be called with the fulfilled value
       * @param rejected   function to be called with the rejection exception
       * @param progressed function to be called on any progress notifications
       * @return promise for the return value from the invoked callback
       */
      Q.when = when;
      function when(value, fulfilled, rejected, progressed) {
        return Q(value).then(fulfilled, rejected, progressed);
      }

      Promise.prototype.thenResolve = function (value) {
        return this.then(function () { return value; });
      };

      Q.thenResolve = function (promise, value) {
        return Q(promise).thenResolve(value);
      };

      Promise.prototype.thenReject = function (reason) {
        return this.then(function () { throw reason; });
      };

      Q.thenReject = function (promise, reason) {
        return Q(promise).thenReject(reason);
      };

      /**
       * If an object is not a promise, it is as "near" as possible.
       * If a promise is rejected, it is as "near" as possible too.
       * If it’s a fulfilled promise, the fulfillment value is nearer.
       * If it’s a deferred promise and the deferred has been resolved, the
       * resolution is "nearer".
       * @param object
       * @returns most resolved (nearest) form of the object
       */

// XXX should we re-do this?
      Q.nearer = nearer;
      function nearer(value) {
        if (isPromise(value)) {
          var inspected = value.inspect();
          if (inspected.state === "fulfilled") {
            return inspected.value;
          }
        }
        return value;
      }

      /**
       * @returns whether the given object is a promise.
       * Otherwise it is a fulfilled value.
       */
      Q.isPromise = isPromise;
      function isPromise(object) {
        return object instanceof Promise;
      }

      Q.isPromiseAlike = isPromiseAlike;
      function isPromiseAlike(object) {
        return isObject(object) && typeof object.then === "function";
      }

      /**
       * @returns whether the given object is a pending promise, meaning not
       * fulfilled or rejected.
       */
      Q.isPending = isPending;
      function isPending(object) {
        return isPromise(object) && object.inspect().state === "pending";
      }

      Promise.prototype.isPending = function () {
        return this.inspect().state === "pending";
      };

      /**
       * @returns whether the given object is a value or fulfilled
       * promise.
       */
      Q.isFulfilled = isFulfilled;
      function isFulfilled(object) {
        return !isPromise(object) || object.inspect().state === "fulfilled";
      }

      Promise.prototype.isFulfilled = function () {
        return this.inspect().state === "fulfilled";
      };

      /**
       * @returns whether the given object is a rejected promise.
       */
      Q.isRejected = isRejected;
      function isRejected(object) {
        return isPromise(object) && object.inspect().state === "rejected";
      }

      Promise.prototype.isRejected = function () {
        return this.inspect().state === "rejected";
      };

//// BEGIN UNHANDLED REJECTION TRACKING

// This promise library consumes exceptions thrown in handlers so they can be
// handled by a subsequent promise.  The exceptions get added to this array when
// they are created, and removed when they are handled.  Note that in ES6 or
// shimmed environments, this would naturally be a `Set`.
      var unhandledReasons = [];
      var unhandledRejections = [];
      var reportedUnhandledRejections = [];
      var trackUnhandledRejections = true;

      function resetUnhandledRejections() {
        unhandledReasons.length = 0;
        unhandledRejections.length = 0;

        if (!trackUnhandledRejections) {
          trackUnhandledRejections = true;
        }
      }

      function trackRejection(promise, reason) {
        if (!trackUnhandledRejections) {
          return;
        }
        if (typeof process === "object" && typeof process.emit === "function") {
          Q.nextTick.runAfter(function () {
            if (array_indexOf(unhandledRejections, promise) !== -1) {
              process.emit("unhandledRejection", reason, promise);
              reportedUnhandledRejections.push(promise);
            }
          });
        }

        unhandledRejections.push(promise);
        if (reason && typeof reason.stack !== "undefined") {
          unhandledReasons.push(reason.stack);
        } else {
          unhandledReasons.push("(no stack) " + reason);
        }
      }

      function untrackRejection(promise) {
        if (!trackUnhandledRejections) {
          return;
        }

        var at = array_indexOf(unhandledRejections, promise);
        if (at !== -1) {
          if (typeof process === "object" && typeof process.emit === "function") {
            Q.nextTick.runAfter(function () {
              var atReport = array_indexOf(reportedUnhandledRejections, promise);
              if (atReport !== -1) {
                process.emit("rejectionHandled", unhandledReasons[at], promise);
                reportedUnhandledRejections.splice(atReport, 1);
              }
            });
          }
          unhandledRejections.splice(at, 1);
          unhandledReasons.splice(at, 1);
        }
      }

      Q.resetUnhandledRejections = resetUnhandledRejections;

      Q.getUnhandledReasons = function () {
        // Make a copy so that consumers can't interfere with our internal state.
        return unhandledReasons.slice();
      };

      Q.stopUnhandledRejectionTracking = function () {
        resetUnhandledRejections();
        trackUnhandledRejections = false;
      };

      resetUnhandledRejections();

//// END UNHANDLED REJECTION TRACKING

      /**
       * Constructs a rejected promise.
       * @param reason value describing the failure
       */
      Q.reject = reject;
      function reject(reason) {
        var rejection = Promise({
          "when": function (rejected) {
            // note that the error has been handled
            if (rejected) {
              untrackRejection(this);
            }
            return rejected ? rejected(reason) : this;
          }
        }, function fallback() {
          return this;
        }, function inspect() {
          return { state: "rejected", reason: reason };
        });

        // Note that the reason has not been handled.
        trackRejection(rejection, reason);

        return rejection;
      }

      /**
       * Constructs a fulfilled promise for an immediate reference.
       * @param value immediate reference
       */
      Q.fulfill = fulfill;
      function fulfill(value) {
        return Promise({
          "when": function () {
            return value;
          },
          "get": function (name) {
            return value[name];
          },
          "set": function (name, rhs) {
            value[name] = rhs;
          },
          "delete": function (name) {
            delete value[name];
          },
          "post": function (name, args) {
            // Mark Miller proposes that post with no name should apply a
            // promised function.
            if (name === null || name === void 0) {
              return value.apply(void 0, args);
            } else {
              return value[name].apply(value, args);
            }
          },
          "apply": function (thisp, args) {
            return value.apply(thisp, args);
          },
          "keys": function () {
            return object_keys(value);
          }
        }, void 0, function inspect() {
          return { state: "fulfilled", value: value };
        });
      }

      /**
       * Converts thenables to Q promises.
       * @param promise thenable promise
       * @returns a Q promise
       */
      function coerce(promise) {
        var deferred = defer();
        Q.nextTick(function () {
          try {
            promise.then(deferred.resolve, deferred.reject, deferred.notify);
          } catch (exception) {
            deferred.reject(exception);
          }
        });
        return deferred.promise;
      }

      /**
       * Annotates an object such that it will never be
       * transferred away from this process over any promise
       * communication channel.
       * @param object
       * @returns promise a wrapping of that object that
       * additionally responds to the "isDef" message
       * without a rejection.
       */
      Q.master = master;
      function master(object) {
        return Promise({
          "isDef": function () {}
        }, function fallback(op, args) {
          return dispatch(object, op, args);
        }, function () {
          return Q(object).inspect();
        });
      }

      /**
       * Spreads the values of a promised array of arguments into the
       * fulfillment callback.
       * @param fulfilled callback that receives variadic arguments from the
       * promised array
       * @param rejected callback that receives the exception if the promise
       * is rejected.
       * @returns a promise for the return value or thrown exception of
       * either callback.
       */
      Q.spread = spread;
      function spread(value, fulfilled, rejected) {
        return Q(value).spread(fulfilled, rejected);
      }

      Promise.prototype.spread = function (fulfilled, rejected) {
        return this.all().then(function (array) {
          return fulfilled.apply(void 0, array);
        }, rejected);
      };

      /**
       * The async function is a decorator for generator functions, turning
       * them into asynchronous generators.  Although generators are only part
       * of the newest ECMAScript 6 drafts, this code does not cause syntax
       * errors in older engines.  This code should continue to work and will
       * in fact improve over time as the language improves.
       *
       * ES6 generators are currently part of V8 version 3.19 with the
       * --harmony-generators runtime flag enabled.  SpiderMonkey has had them
       * for longer, but under an older Python-inspired form.  This function
       * works on both kinds of generators.
       *
       * Decorates a generator function such that:
       *  - it may yield promises
       *  - execution will continue when that promise is fulfilled
       *  - the value of the yield expression will be the fulfilled value
       *  - it returns a promise for the return value (when the generator
       *    stops iterating)
       *  - the decorated function returns a promise for the return value
       *    of the generator or the first rejected promise among those
       *    yielded.
       *  - if an error is thrown in the generator, it propagates through
       *    every following yield until it is caught, or until it escapes
       *    the generator function altogether, and is translated into a
       *    rejection for the promise returned by the decorated generator.
       */
      Q.async = async;
      function async(makeGenerator) {
        return function () {
          // when verb is "send", arg is a value
          // when verb is "throw", arg is an exception
          function continuer(verb, arg) {
            var result;

            // Until V8 3.19 / Chromium 29 is released, SpiderMonkey is the only
            // engine that has a deployed base of browsers that support generators.
            // However, SM's generators use the Python-inspired semantics of
            // outdated ES6 drafts.  We would like to support ES6, but we'd also
            // like to make it possible to use generators in deployed browsers, so
            // we also support Python-style generators.  At some point we can remove
            // this block.

            if (typeof StopIteration === "undefined") {
              // ES6 Generators
              try {
                result = generator[verb](arg);
              } catch (exception) {
                return reject(exception);
              }
              if (result.done) {
                return Q(result.value);
              } else {
                return when(result.value, callback, errback);
              }
            } else {
              // SpiderMonkey Generators
              // FIXME: Remove this case when SM does ES6 generators.
              try {
                result = generator[verb](arg);
              } catch (exception) {
                if (isStopIteration(exception)) {
                  return Q(exception.value);
                } else {
                  return reject(exception);
                }
              }
              return when(result, callback, errback);
            }
          }
          var generator = makeGenerator.apply(this, arguments);
          var callback = continuer.bind(continuer, "next");
          var errback = continuer.bind(continuer, "throw");
          return callback();
        };
      }

      /**
       * The spawn function is a small wrapper around async that immediately
       * calls the generator and also ends the promise chain, so that any
       * unhandled errors are thrown instead of forwarded to the error
       * handler. This is useful because it's extremely common to run
       * generators at the top-level to work with libraries.
       */
      Q.spawn = spawn;
      function spawn(makeGenerator) {
        Q.done(Q.async(makeGenerator)());
      }

// FIXME: Remove this interface once ES6 generators are in SpiderMonkey.
      /**
       * Throws a ReturnValue exception to stop an asynchronous generator.
       *
       * This interface is a stop-gap measure to support generator return
       * values in older Firefox/SpiderMonkey.  In browsers that support ES6
       * generators like Chromium 29, just use "return" in your generator
       * functions.
       *
       * @param value the return value for the surrounding generator
       * @throws ReturnValue exception with the value.
       * @example
       * // ES6 style
       * Q.async(function* () {
 *      var foo = yield getFooPromise();
 *      var bar = yield getBarPromise();
 *      return foo + bar;
 * })
       * // Older SpiderMonkey style
       * Q.async(function () {
 *      var foo = yield getFooPromise();
 *      var bar = yield getBarPromise();
 *      Q.return(foo + bar);
 * })
       */
      Q["return"] = _return;
      function _return(value) {
        throw new QReturnValue(value);
      }

      /**
       * The promised function decorator ensures that any promise arguments
       * are settled and passed as values (`this` is also settled and passed
       * as a value).  It will also ensure that the result of a function is
       * always a promise.
       *
       * @example
       * var add = Q.promised(function (a, b) {
 *     return a + b;
 * });
       * add(Q(a), Q(B));
       *
       * @param {function} callback The function to decorate
       * @returns {function} a function that has been decorated.
       */
      Q.promised = promised;
      function promised(callback) {
        return function () {
          return spread([this, all(arguments)], function (self, args) {
            return callback.apply(self, args);
          });
        };
      }

      /**
       * sends a message to a value in a future turn
       * @param object* the recipient
       * @param op the name of the message operation, e.g., "when",
       * @param args further arguments to be forwarded to the operation
       * @returns result {Promise} a promise for the result of the operation
       */
      Q.dispatch = dispatch;
      function dispatch(object, op, args) {
        return Q(object).dispatch(op, args);
      }

      Promise.prototype.dispatch = function (op, args) {
        var self = this;
        var deferred = defer();
        Q.nextTick(function () {
          self.promiseDispatch(deferred.resolve, op, args);
        });
        return deferred.promise;
      };

      /**
       * Gets the value of a property in a future turn.
       * @param object    promise or immediate reference for target object
       * @param name      name of property to get
       * @return promise for the property value
       */
      Q.get = function (object, key) {
        return Q(object).dispatch("get", [key]);
      };

      Promise.prototype.get = function (key) {
        return this.dispatch("get", [key]);
      };

      /**
       * Sets the value of a property in a future turn.
       * @param object    promise or immediate reference for object object
       * @param name      name of property to set
       * @param value     new value of property
       * @return promise for the return value
       */
      Q.set = function (object, key, value) {
        return Q(object).dispatch("set", [key, value]);
      };

      Promise.prototype.set = function (key, value) {
        return this.dispatch("set", [key, value]);
      };

      /**
       * Deletes a property in a future turn.
       * @param object    promise or immediate reference for target object
       * @param name      name of property to delete
       * @return promise for the return value
       */
      Q.del = // XXX legacy
        Q["delete"] = function (object, key) {
          return Q(object).dispatch("delete", [key]);
        };

      Promise.prototype.del = // XXX legacy
        Promise.prototype["delete"] = function (key) {
          return this.dispatch("delete", [key]);
        };

      /**
       * Invokes a method in a future turn.
       * @param object    promise or immediate reference for target object
       * @param name      name of method to invoke
       * @param value     a value to post, typically an array of
       *                  invocation arguments for promises that
       *                  are ultimately backed with `resolve` values,
       *                  as opposed to those backed with URLs
       *                  wherein the posted value can be any
       *                  JSON serializable object.
       * @return promise for the return value
       */
// bound locally because it is used by other methods
      Q.mapply = // XXX As proposed by "Redsandro"
        Q.post = function (object, name, args) {
          return Q(object).dispatch("post", [name, args]);
        };

      Promise.prototype.mapply = // XXX As proposed by "Redsandro"
        Promise.prototype.post = function (name, args) {
          return this.dispatch("post", [name, args]);
        };

      /**
       * Invokes a method in a future turn.
       * @param object    promise or immediate reference for target object
       * @param name      name of method to invoke
       * @param ...args   array of invocation arguments
       * @return promise for the return value
       */
      Q.send = // XXX Mark Miller's proposed parlance
        Q.mcall = // XXX As proposed by "Redsandro"
          Q.invoke = function (object, name /*...args*/) {
            return Q(object).dispatch("post", [name, array_slice(arguments, 2)]);
          };

      Promise.prototype.send = // XXX Mark Miller's proposed parlance
        Promise.prototype.mcall = // XXX As proposed by "Redsandro"
          Promise.prototype.invoke = function (name /*...args*/) {
            return this.dispatch("post", [name, array_slice(arguments, 1)]);
          };

      /**
       * Applies the promised function in a future turn.
       * @param object    promise or immediate reference for target function
       * @param args      array of application arguments
       */
      Q.fapply = function (object, args) {
        return Q(object).dispatch("apply", [void 0, args]);
      };

      Promise.prototype.fapply = function (args) {
        return this.dispatch("apply", [void 0, args]);
      };

      /**
       * Calls the promised function in a future turn.
       * @param object    promise or immediate reference for target function
       * @param ...args   array of application arguments
       */
      Q["try"] =
        Q.fcall = function (object /* ...args*/) {
          return Q(object).dispatch("apply", [void 0, array_slice(arguments, 1)]);
        };

      Promise.prototype.fcall = function (/*...args*/) {
        return this.dispatch("apply", [void 0, array_slice(arguments)]);
      };

      /**
       * Binds the promised function, transforming return values into a fulfilled
       * promise and thrown errors into a rejected one.
       * @param object    promise or immediate reference for target function
       * @param ...args   array of application arguments
       */
      Q.fbind = function (object /*...args*/) {
        var promise = Q(object);
        var args = array_slice(arguments, 1);
        return function fbound() {
          return promise.dispatch("apply", [
            this,
            args.concat(array_slice(arguments))
          ]);
        };
      };
      Promise.prototype.fbind = function (/*...args*/) {
        var promise = this;
        var args = array_slice(arguments);
        return function fbound() {
          return promise.dispatch("apply", [
            this,
            args.concat(array_slice(arguments))
          ]);
        };
      };

      /**
       * Requests the names of the owned properties of a promised
       * object in a future turn.
       * @param object    promise or immediate reference for target object
       * @return promise for the keys of the eventually settled object
       */
      Q.keys = function (object) {
        return Q(object).dispatch("keys", []);
      };

      Promise.prototype.keys = function () {
        return this.dispatch("keys", []);
      };

      /**
       * Turns an array of promises into a promise for an array.  If any of
       * the promises gets rejected, the whole array is rejected immediately.
       * @param {Array*} an array (or promise for an array) of values (or
       * promises for values)
       * @returns a promise for an array of the corresponding values
       */
// By Mark Miller
// http://wiki.ecmascript.org/doku.php?id=strawman:concurrency&rev=1308776521#allfulfilled
      Q.all = all;
      function all(promises) {
        return when(promises, function (promises) {
          var pendingCount = 0;
          var deferred = defer();
          array_reduce(promises, function (undefined, promise, index) {
            var snapshot;
            if (
              isPromise(promise) &&
              (snapshot = promise.inspect()).state === "fulfilled"
            ) {
              promises[index] = snapshot.value;
            } else {
              ++pendingCount;
              when(
                promise,
                function (value) {
                  promises[index] = value;
                  if (--pendingCount === 0) {
                    deferred.resolve(promises);
                  }
                },
                deferred.reject,
                function (progress) {
                  deferred.notify({ index: index, value: progress });
                }
              );
            }
          }, void 0);
          if (pendingCount === 0) {
            deferred.resolve(promises);
          }
          return deferred.promise;
        });
      }

      Promise.prototype.all = function () {
        return all(this);
      };

      /**
       * Returns the first resolved promise of an array. Prior rejected promises are
       * ignored.  Rejects only if all promises are rejected.
       * @param {Array*} an array containing values or promises for values
       * @returns a promise fulfilled with the value of the first resolved promise,
       * or a rejected promise if all promises are rejected.
       */
      Q.any = any;

      function any(promises) {
        if (promises.length === 0) {
          return Q.resolve();
        }

        var deferred = Q.defer();
        var pendingCount = 0;
        array_reduce(promises, function (prev, current, index) {
          var promise = promises[index];

          pendingCount++;

          when(promise, onFulfilled, onRejected, onProgress);
          function onFulfilled(result) {
            deferred.resolve(result);
          }
          function onRejected() {
            pendingCount--;
            if (pendingCount === 0) {
              deferred.reject(new Error(
                "Can't get fulfillment value from any promise, all " +
                "promises were rejected."
              ));
            }
          }
          function onProgress(progress) {
            deferred.notify({
              index: index,
              value: progress
            });
          }
        }, undefined);

        return deferred.promise;
      }

      Promise.prototype.any = function () {
        return any(this);
      };

      /**
       * Waits for all promises to be settled, either fulfilled or
       * rejected.  This is distinct from `all` since that would stop
       * waiting at the first rejection.  The promise returned by
       * `allResolved` will never be rejected.
       * @param promises a promise for an array (or an array) of promises
       * (or values)
       * @return a promise for an array of promises
       */
      Q.allResolved = deprecate(allResolved, "allResolved", "allSettled");
      function allResolved(promises) {
        return when(promises, function (promises) {
          promises = array_map(promises, Q);
          return when(all(array_map(promises, function (promise) {
            return when(promise, noop, noop);
          })), function () {
            return promises;
          });
        });
      }

      Promise.prototype.allResolved = function () {
        return allResolved(this);
      };

      /**
       * @see Promise#allSettled
       */
      Q.allSettled = allSettled;
      function allSettled(promises) {
        return Q(promises).allSettled();
      }

      /**
       * Turns an array of promises into a promise for an array of their states (as
       * returned by `inspect`) when they have all settled.
       * @param {Array[Any*]} values an array (or promise for an array) of values (or
       * promises for values)
       * @returns {Array[State]} an array of states for the respective values.
       */
      Promise.prototype.allSettled = function () {
        return this.then(function (promises) {
          return all(array_map(promises, function (promise) {
            promise = Q(promise);
            function regardless() {
              return promise.inspect();
            }
            return promise.then(regardless, regardless);
          }));
        });
      };

      /**
       * Captures the failure of a promise, giving an oportunity to recover
       * with a callback.  If the given promise is fulfilled, the returned
       * promise is fulfilled.
       * @param {Any*} promise for something
       * @param {Function} callback to fulfill the returned promise if the
       * given promise is rejected
       * @returns a promise for the return value of the callback
       */
      Q.fail = // XXX legacy
        Q["catch"] = function (object, rejected) {
          return Q(object).then(void 0, rejected);
        };

      Promise.prototype.fail = // XXX legacy
        Promise.prototype["catch"] = function (rejected) {
          return this.then(void 0, rejected);
        };

      /**
       * Attaches a listener that can respond to progress notifications from a
       * promise's originating deferred. This listener receives the exact arguments
       * passed to ``deferred.notify``.
       * @param {Any*} promise for something
       * @param {Function} callback to receive any progress notifications
       * @returns the given promise, unchanged
       */
      Q.progress = progress;
      function progress(object, progressed) {
        return Q(object).then(void 0, void 0, progressed);
      }

      Promise.prototype.progress = function (progressed) {
        return this.then(void 0, void 0, progressed);
      };

      /**
       * Provides an opportunity to observe the settling of a promise,
       * regardless of whether the promise is fulfilled or rejected.  Forwards
       * the resolution to the returned promise when the callback is done.
       * The callback can return a promise to defer completion.
       * @param {Any*} promise
       * @param {Function} callback to observe the resolution of the given
       * promise, takes no arguments.
       * @returns a promise for the resolution of the given promise when
       * ``fin`` is done.
       */
      Q.fin = // XXX legacy
        Q["finally"] = function (object, callback) {
          return Q(object)["finally"](callback);
        };

      Promise.prototype.fin = // XXX legacy
        Promise.prototype["finally"] = function (callback) {
          callback = Q(callback);
          return this.then(function (value) {
            return callback.fcall().then(function () {
              return value;
            });
          }, function (reason) {
            // TODO attempt to recycle the rejection with "this".
            return callback.fcall().then(function () {
              throw reason;
            });
          });
        };

      /**
       * Terminates a chain of promises, forcing rejections to be
       * thrown as exceptions.
       * @param {Any*} promise at the end of a chain of promises
       * @returns nothing
       */
      Q.done = function (object, fulfilled, rejected, progress) {
        return Q(object).done(fulfilled, rejected, progress);
      };

      Promise.prototype.done = function (fulfilled, rejected, progress) {
        var onUnhandledError = function (error) {
          // forward to a future turn so that ``when``
          // does not catch it and turn it into a rejection.
          Q.nextTick(function () {
            makeStackTraceLong(error, promise);
            if (Q.onerror) {
              Q.onerror(error);
            } else {
              throw error;
            }
          });
        };

        // Avoid unnecessary `nextTick`ing via an unnecessary `when`.
        var promise = fulfilled || rejected || progress ?
          this.then(fulfilled, rejected, progress) :
          this;

        if (typeof process === "object" && process && process.domain) {
          onUnhandledError = process.domain.bind(onUnhandledError);
        }

        promise.then(void 0, onUnhandledError);
      };

      /**
       * Causes a promise to be rejected if it does not get fulfilled before
       * some milliseconds time out.
       * @param {Any*} promise
       * @param {Number} milliseconds timeout
       * @param {Any*} custom error message or Error object (optional)
       * @returns a promise for the resolution of the given promise if it is
       * fulfilled before the timeout, otherwise rejected.
       */
      Q.timeout = function (object, ms, error) {
        return Q(object).timeout(ms, error);
      };

      Promise.prototype.timeout = function (ms, error) {
        var deferred = defer();
        var timeoutId = setTimeout(function () {
          if (!error || "string" === typeof error) {
            error = new Error(error || "Timed out after " + ms + " ms");
            error.code = "ETIMEDOUT";
          }
          deferred.reject(error);
        }, ms);

        this.then(function (value) {
          clearTimeout(timeoutId);
          deferred.resolve(value);
        }, function (exception) {
          clearTimeout(timeoutId);
          deferred.reject(exception);
        }, deferred.notify);

        return deferred.promise;
      };

      /**
       * Returns a promise for the given value (or promised value), some
       * milliseconds after it resolved. Passes rejections immediately.
       * @param {Any*} promise
       * @param {Number} milliseconds
       * @returns a promise for the resolution of the given promise after milliseconds
       * time has elapsed since the resolution of the given promise.
       * If the given promise rejects, that is passed immediately.
       */
      Q.delay = function (object, timeout) {
        if (timeout === void 0) {
          timeout = object;
          object = void 0;
        }
        return Q(object).delay(timeout);
      };

      Promise.prototype.delay = function (timeout) {
        return this.then(function (value) {
          var deferred = defer();
          setTimeout(function () {
            deferred.resolve(value);
          }, timeout);
          return deferred.promise;
        });
      };

      /**
       * Passes a continuation to a Node function, which is called with the given
       * arguments provided as an array, and returns a promise.
       *
       *      Q.nfapply(FS.readFile, [__filename])
       *      .then(function (content) {
 *      })
       *
       */
      Q.nfapply = function (callback, args) {
        return Q(callback).nfapply(args);
      };

      Promise.prototype.nfapply = function (args) {
        var deferred = defer();
        var nodeArgs = array_slice(args);
        nodeArgs.push(deferred.makeNodeResolver());
        this.fapply(nodeArgs).fail(deferred.reject);
        return deferred.promise;
      };

      /**
       * Passes a continuation to a Node function, which is called with the given
       * arguments provided individually, and returns a promise.
       * @example
       * Q.nfcall(FS.readFile, __filename)
       * .then(function (content) {
 * })
       *
       */
      Q.nfcall = function (callback /*...args*/) {
        var args = array_slice(arguments, 1);
        return Q(callback).nfapply(args);
      };

      Promise.prototype.nfcall = function (/*...args*/) {
        var nodeArgs = array_slice(arguments);
        var deferred = defer();
        nodeArgs.push(deferred.makeNodeResolver());
        this.fapply(nodeArgs).fail(deferred.reject);
        return deferred.promise;
      };

      /**
       * Wraps a NodeJS continuation passing function and returns an equivalent
       * version that returns a promise.
       * @example
       * Q.nfbind(FS.readFile, __filename)("utf-8")
       * .then(console.log)
       * .done()
       */
      Q.nfbind =
        Q.denodeify = function (callback /*...args*/) {
          var baseArgs = array_slice(arguments, 1);
          return function () {
            var nodeArgs = baseArgs.concat(array_slice(arguments));
            var deferred = defer();
            nodeArgs.push(deferred.makeNodeResolver());
            Q(callback).fapply(nodeArgs).fail(deferred.reject);
            return deferred.promise;
          };
        };

      Promise.prototype.nfbind =
        Promise.prototype.denodeify = function (/*...args*/) {
          var args = array_slice(arguments);
          args.unshift(this);
          return Q.denodeify.apply(void 0, args);
        };

      Q.nbind = function (callback, thisp /*...args*/) {
        var baseArgs = array_slice(arguments, 2);
        return function () {
          var nodeArgs = baseArgs.concat(array_slice(arguments));
          var deferred = defer();
          nodeArgs.push(deferred.makeNodeResolver());
          function bound() {
            return callback.apply(thisp, arguments);
          }
          Q(bound).fapply(nodeArgs).fail(deferred.reject);
          return deferred.promise;
        };
      };

      Promise.prototype.nbind = function (/*thisp, ...args*/) {
        var args = array_slice(arguments, 0);
        args.unshift(this);
        return Q.nbind.apply(void 0, args);
      };

      /**
       * Calls a method of a Node-style object that accepts a Node-style
       * callback with a given array of arguments, plus a provided callback.
       * @param object an object that has the named method
       * @param {String} name name of the method of object
       * @param {Array} args arguments to pass to the method; the callback
       * will be provided by Q and appended to these arguments.
       * @returns a promise for the value or error
       */
      Q.nmapply = // XXX As proposed by "Redsandro"
        Q.npost = function (object, name, args) {
          return Q(object).npost(name, args);
        };

      Promise.prototype.nmapply = // XXX As proposed by "Redsandro"
        Promise.prototype.npost = function (name, args) {
          var nodeArgs = array_slice(args || []);
          var deferred = defer();
          nodeArgs.push(deferred.makeNodeResolver());
          this.dispatch("post", [name, nodeArgs]).fail(deferred.reject);
          return deferred.promise;
        };

      /**
       * Calls a method of a Node-style object that accepts a Node-style
       * callback, forwarding the given variadic arguments, plus a provided
       * callback argument.
       * @param object an object that has the named method
       * @param {String} name name of the method of object
       * @param ...args arguments to pass to the method; the callback will
       * be provided by Q and appended to these arguments.
       * @returns a promise for the value or error
       */
      Q.nsend = // XXX Based on Mark Miller's proposed "send"
        Q.nmcall = // XXX Based on "Redsandro's" proposal
          Q.ninvoke = function (object, name /*...args*/) {
            var nodeArgs = array_slice(arguments, 2);
            var deferred = defer();
            nodeArgs.push(deferred.makeNodeResolver());
            Q(object).dispatch("post", [name, nodeArgs]).fail(deferred.reject);
            return deferred.promise;
          };

      Promise.prototype.nsend = // XXX Based on Mark Miller's proposed "send"
        Promise.prototype.nmcall = // XXX Based on "Redsandro's" proposal
          Promise.prototype.ninvoke = function (name /*...args*/) {
            var nodeArgs = array_slice(arguments, 1);
            var deferred = defer();
            nodeArgs.push(deferred.makeNodeResolver());
            this.dispatch("post", [name, nodeArgs]).fail(deferred.reject);
            return deferred.promise;
          };

      /**
       * If a function would like to support both Node continuation-passing-style and
       * promise-returning-style, it can end its internal promise chain with
       * `nodeify(nodeback)`, forwarding the optional nodeback argument.  If the user
       * elects to use a nodeback, the result will be sent there.  If they do not
       * pass a nodeback, they will receive the result promise.
       * @param object a result (or a promise for a result)
       * @param {Function} nodeback a Node.js-style callback
       * @returns either the promise or nothing
       */
      Q.nodeify = nodeify;
      function nodeify(object, nodeback) {
        return Q(object).nodeify(nodeback);
      }

      Promise.prototype.nodeify = function (nodeback) {
        if (nodeback) {
          this.then(function (value) {
            Q.nextTick(function () {
              nodeback(null, value);
            });
          }, function (error) {
            Q.nextTick(function () {
              nodeback(error);
            });
          });
        } else {
          return this;
        }
      };

      Q.noConflict = function() {
        throw new Error("Q.noConflict only works when Q is used as a global");
      };

// All code before this point will be filtered from stack traces.
      var qEndingLine = captureLine();

      return Q;

    });

  }).call(this,require('_process'))
},{"_process":5}]},{},[7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32]);
